972322, 07 AM DotNet Securty - OWASP Cheat Sheet Series
DotNet Security Cheat Sheet
Introduction
This page intends to provide quick basic NET security tips for developers.
The .NET Framework
‘The .NET Framework is Microsofts principal platform for enterprise development. Itis the
supporting API for ASP.NET, Windows Desktop applications, Windows Communication Foundation
services, SharePoint, Visual Studio Tools for Office and other technologies.
Updating the Framework
‘The .NET Framework is kept up-to-date by Microsoft with the Windows Update service. Developers
do not normally need to run separate updates to the Framework. Windows Update can be
accessed at Windows Update or from the Windews Update program ona Windows computer.
Indvidual frameworks can be kept up to date using NuGet. As Visual Studio prompts for updates,
build itintoyour lifecycle.
Remember that third-party libraries have to be updated separately andnct all cf them use NuGet.
ELMAH for instance, requites a separate update effort.
‘Security Announcements
Receive seaurity notifications by selecting the "Watch" button at the following repositories:
NET Core Security Announcements
«ASPET Core & Entity Framework Core Security Announcements
-NET Framework Guidance
The NET Framework is the set of APIs that support an advanced type system, data, graptics,
network, file handling and most of the rest of what is needed to write enterprise apps inthe
‘ntps:ifcheatshectseries.owasp.oricheatsheets/DotNet_Securty_Cheat_Sheethtml 1128972322, 07 AM DotNet Securty - OWASP Cheat Sheet Series
Microsoft ecosystem. it is aneerly ubiquitous library that is strongly named and versioned at the
assembly level.
Data Access
+ Use Parameterized SOL commends for all data access, without exception.
* Donot use SqiGommand witha string parameter made up of a concatenated SQL String.
«List allowable values coming from the user. Use enums, TryParse or lookup values to assure
that the data coming from the user is as expected.
+ Enumsare still vulnerable to unexpected values because .NET only validates a successful
cast to the underlying data type. integer by default. Enum. IsDefined can validate whether
the input value is valid within the list of defined constants.
‘+ Apply the principle of least privilege when setting up the Database User in your database of
choice. The database user should only be able to aocess items that make sense for the use
case.
‘Use of the Entity Framework isa very effective SQL injection prevention mechanism.
Remember that building your awn ad hoc queries in Entity Framework is just as susceptible
to SQLi as a plain SQL query.
«© When using SQL Server, prefer integrated authentication over SQL authentication.
‘+ Use Always Encrypted where possible for sensitive data (SQL Server 2016andSQL Azure),
Encryption
+ Never, ever write your own encryption,
‘© Use the Windows Data Protection API (DPAPI) for secure local storage of sensitive data.
‘Use astrong hash algorithm.
‘+ In.NET (both Framework and Core) the strongest hashing algorithm for general hashing
tequiementsis System Security.Cryptography.SHAS12.
‘+ Inthe NET framework the strongest algorithm for password hashingis PBKDF2,
implemented as System Security Cryptography. Ric2898DeriveBytes,
‘+ In.NET Core the strongest algorithm for password hashing is PBKDF2, implemented as
Microsoft. AspNetCore. Cryptography KeyDerivation.Pbkaf2 which has several significant
advantages over Rfc2898DeriveBytes.
‘+ Whenusing a hashing function to hash nor-unique inputs such as passwords, use a salt
value added to the original value before hashing.
‘ntps:ifcheatshectseries.owasp.oricheatsheets/DotNet_Securty_Cheat_Sheethtml 2128972322, 07 AM DotNet Securty - OWASP Cheat Sheet Series
‘Make sure your application or protocol can easily support a future change of cryptographic
algorithms.
‘+ Use NuGet to keep alll of your packages up to date. Watch the updates on your development
‘setup, and plan updates to your applications accordingly.
General
+ Lock down the config file,
+ Remove all aspects of configuration that are nctin use.
«Encrypt sensitive parts of the web.config using espnet_regiis -pe (command line
help).
+ For Click Once applications, the NET Framework should be upgraded to use the latest version
toensure LS 1.2 or later support.
ASP NET Web Forms Guidance
ASP.NET Web Forms is the original browser-based application development AP for the NET
framework, and is still the most common enterprise platform for web application development.
© Alwaysuse HTTPS.
Enable requireSSL on cookies and form elements and HttpOnly on cookies in the web.config.
Implement customErrors,
‘* Make sure tracing is tumed off.
While viewstate isnt always appropricte for web development, usingit can provide CSRF
mitigation. To make the ViewState protect against CSRF attacks youneed to set the
ViewStateUserkey:
protected override Oninit(Eventargs e) {
base.OnInit(e);
ViewStateUserKey = Session.SessionI0;
}
If you dontt use Viewstate, then lock to the default master page of the ASPNET Web Forms default
template for a manual anti-CSRF token using a double-submit cookie.
private const string AntixsrfTokenkey =
privete const string AntixsrfUserNamekey =
private string _entixsrfTokenValue;
protected void Page_Init(object sender, EventArgs e)
Antixsr Token" ;
AntixerfUserName" ;
‘ntps:ifcheatshectseries.owasp.oricheatsheets/DotNet_Securty_Cheat_Sheethtml 289123/22, 9:07 AM DotNet Securty - OWASP Cheat Sheet Series
{
// The code below helps to protect against XSRF attacks
var requestCookie = Request.Cookies|Antixsr fTokenKey
Guid requestCookieGuidvalue;
if (requestCookie != null 8& Guid, TryParse(requestCookie.Velue, out requestCook
{
// Use the Anti-XSRF token from the cookie
antixsrfTokenValue = requestCookie.Value;
Page.ViewStateUserkey = _ontiXsrfTokenValue;
}
else
{
11 Generate @ new Anti-XSRF token and save to the cookie
~antixsrfTokenValue = Guid.New6uid().ToString(’N");
Page.ViewStateUserkey = antiXsrfTokenValue;
var responseCookie = new HttpCookie(AntixsrTokenkey)
{
Hetponly = true,
Value = antixsrfTokenValue
ip
Af (FormsAuthentication-RequireSSl && Request .IsSecureConnection)
{
responseCookie.Secure = true;
}
Response.Cookies.Set(responseCookie);
}
Page.PreLoad += master_Page_Pretoad;
}
protected void master_Page_PreLoad(object sender, EventArgs e)
{
Af (1TsPostBack)
{
11 Set Anti-XSRF token
ViewState[Antixsr fTokenkey] = Page.ViewStateUserKey ;
ViewState[ AntiXsrfUserNaneKey] = Context.User-Identity.Name 22 String.Empty;
}
else
{
// Nalidate the Anti-XSRF token
af ((string)ViewState[Antixsr fTokenkey]
(string)Viewstate[AntixsrfUserNameKey]
-antixsrfTokenValue ||
(Context.User .Identity.Name 7?
4
‘throw new InvalidOperationException("Validation of Anti-
XSRF token failed.”);
+
+
# Consider HSTS inllS, See here for the procedure,
‘ntps:ifcheatshectseries.owasp.oricheatsheets/DotNet_Securty_Cheat_Sheethtml 439123/22, 9:07 AM DotNet Securty - OWASP Cheat Sheet Series
‘© This isa recommended wed.config setup that handles HSTS among other things.
‘
value="default-sre ‘none’; style-sre ‘self’; img-sre ‘self'; font-sre
‘self'" (>
match url="(.*)"/>
action type="Rewrite” value="max-age=15768000" />
true” />
‘ntps:ifcheatshectseries.owasp.oricheatsheets/DotNet_Securty_Cheat_Sheethtml 51289123122, 107 AM
DotNet Securty - OWASP Cheat Sheet Series
Remove the version header by adding the following linein achine.config file:
‘ntps:ifcheatshectseries.owasp.oricheatsheets/DotNet_Securty_Cheat_Sheethtml 8123972322, 07 AM DotNet Securty - OWASP Cheat Sheet Series
else
{
//ipaddress
,
}
not of type IPAddress
DO: Try to only accept characters which are simple alphanumeric.
DO NOT: Assume you can sanitize special characters without actually remaving them. Various
combinations of \, ° and @ may have an unexpected impact on sanitization attempts.
DO NOT: Rely on methods without a security guarantee.
eg. .NET Core 22 and greater and .NET 5 and greater support ProcessStartinfo. ArgumentList
which performs some character escaping but itis not clear if thisis guaranteed to be secure.
DO: Look at altematives to passing raw untrusted arguments via command-line parameters such
{as encoding using Base64 (which would safely encode any special characters as well) and then
decode the parameters in the receiving appication..
LDAP injection
‘Almost any characters canbe used in Distinguished Nemes. However, some must be escaped with
the backslash \ escape character. A table showing which characters that should be escaped for
Active Directory can be foundat the in the LDAP Injection Prevention Cheat Sheet.
NB: The space character must be escaped only if itis the leading or tralling character in a
component name, such asa Common Name. Embedded spaces should nt be escaped.
More information can be found here.
A2 Broken Authentication
DO: Use ASPrnet Core Identity, ASPnet Core klentity framework is well configuredby default, where
ituses secure password hashes and an individual salt. entity uses the PBKDF2 hashing function
for passwords, and they generate a random salt per user.
DO: Set secure passwerd policy
e.g ASPnet Core Kentity
//startup.cs
services, Configure(options =>
{
‘ntps:ifcheatshectseries.owasp.oricheatsheets/DotNet_Securty_Cheat_Sheethtml 9128972322, 07 AM DotNet Securty - OWASP Cheat Sheet Series
// Password settings
options. Password, RequireDigit
options. Password.RequiredLength = 8;
options. Password.RequireNonAlphanumeric
options, Password.RequireUppercase = true;
options. Password. RequireLonercase
options, Password.RequiredUniqueChars = 6;
options. Lockout .Defaul tLockoutTimeSpan = TimeSpan.FronMinutes(30) ;
options. Lockout.MaxFailedaccessAttempts = 3;
options. Signin.RequireConfirmedEmail = true;
options. User RequireUniquetmail = tru
dD:
Do: Seta cookie policy
eg
//startup.cs
services.ConfigureApplicationCookie(options =>
{
options,Cookie.HttpOnly = true;
options.Cookie. Expiration = TimeSpan,FromMours(1)
options.SlidingExpiration = true;
dv:
A3 Sensitive Data Exposure
DO NOT: Store encrypted passwords.
DO: Usea stronghash to store password credentials. For hash refer to this section,
DO: Enforce passwords with a minimum complexity thet will survive a dictionary attack ie. longer
passwords that use the full character set (numbers, symbols and letters) to increase the entropy.
DO: Use a strong enayption routine such as AES-512 where personally identifiable data needs to
be restored to it's original format. Protect encryption keys more than any other asset, please find
more information of storing encryption keys at rest. Apply the following test: Would you be happy
leaving the data ona spreadsheet on a bus for everyone to read. Assume the attacker can get
drrect access to your database and protect it accordingly. More information can be found here.
DO: Use TLS 1.2 for your entire site, Get a free certificate LetsEncrypt.org.
DO NOT: Allow SSL, this is now obsolete,
‘ntps:ifcheatshectseries.owasp.oricheatsheets/DotNet_Securty_Cheat_Sheethtml 103972322, 07 AM DotNet Securty - OWASP Cheat Sheet Series
DO: Have a strong TLS policy (see SSI. Best Practices), use TLS 1.2 wherever possible, Then check
the configurationusing SSI. Test or TestSSl.
DO: Ensure headers are not disclosing information about your application. See HttpHleaders.cs,
Dionach StripHeaders, disable via web .config or startup.cs:
More information on Transport Layer Protection can be found here. e.g Web.config
true” />
egStartup.cs
app.UseHsts(hsts => hsts.MaxAge(365).IncludeSubdomains() );
app. UseXContent Typedptions() ;
app. UseReferrerPolicy(opts => opts.NoReferrer());
app. UseXXssProtection(options => options.FilterDisabled()) ;
app.UseXfo(options = options.Deny()) ;
app.UseCsp(opts => opts
-BlockAlIMixedContent()
«StyleSources(s > s.Self())
+StyleSources(s => s.Unsafelnline())
-FontSources(s => s.Self())
-FormActions(s => s.Self())
-FrameAncestors(s => s.Self())
sTmageSources(s => s.Self())
-SeriptSources(s => s.Self())
vu
For more information about headers can be found here,
A4 XML External Entities (XXE)
‘ntps:ifcheatshectseries.owasp.oricheatsheets/DotNet_Securty_Cheat_Sheethtml ses972322, 07 AM DotNet Securty - OWASP Cheat Sheet Series
XXE attacks occur when an XML parse does nct properly process user input that contains extemal
entity declaration in the doctype of an XML payload.
‘This article discusses the most common XML Processing Options for NET.
Please refer to the XXE cheat sheet for more detailed information on preventing XXE and other
XML Denial of Service attacks.
AS Broken Access Control
Weak Account management
Ensure cookies are sent via httpOnly:
Cookielittponly = true,
Reduce the time period a session can be stolenin ty reducing session timeout and removing
sliding expiration:
ExpireTimeSpan = TimeSpan.Frominutes(6®),
SlidingExpiration = false
See here for full startup code snippet
Ensure cookie is sent cver HTTPS in the production environment This should be enforcedin the
config transforms:
rue" xdt:Transform="Setattributes(requireSsL)"/>
rue" xdt:Transform="Setattributes(requireSsL)"/>
Protect LogOn, Registration and password reset methods against brute force attacks by throttling
Tequests (see code below), consider also using ReCaptcha.
[HttpPost]
[ALlowAnonyous]
[alidateantiForgeryToken]
TALlowXRequest sEveryxSecondsattribute(Name = "Logon",
Message = "You have performed this action nore than {x} times in the last {n}
seconds.
Requests = 3, Seconds = 66)]
public async TaskeActionResult> LogOn(LogOnViewModel model, string returnUrl)
‘ntps:ifcheatshectseries.owasp.oricheatsheets/DotNet_Securty_Cheat_Sheethtml 123DotNet Securty - OWASP Cheat Sheet Series
DO NOT: Roll your own authentication or session management, use the one provided by Net
DO NOT: Tell someone if the account exists on LogOn, Registration or Password reset. Say
something like Either the username or password was incorrect, or ‘if this account e
reset token will be sent to the registered email address. This protects against account
‘enumeration
s then a
‘The feedback to the user should be identical whether or not the account exists, both in terms of
content and behavior: e.g. if the response takes 50% longer when the account is real then
membership information can be guessed and tested.
Missing function-level access control
DO: Authorize users on all externally facing endpoints. The .NET framework has many ways to
authorize a user, use them at method level:
[Authorize(Roles = "Admin" }
[Httpcet]
Public ActionResult Index(int page
or better yet, at controller level
[Authorize]
public class UserController
You can also check roles in code using identity features in net
‘System.Web. Security.Roles.IsUserInRole(userName, roleName)
You can find more information here on Access Control and here for Authorization.
Insecure Direct object references
When you have a resource (object) which can be accessed by a reference (in the sample below this
isthe id) then you need to ensure that the user is intended to be there
// Insecure
public ActionResult Edit(int id)
4
var user = context .Users.First0rdefault(e => e.Id
return View("Details", new UserViewModel (user);
}
// Secure
public ActionResult Edit(int id)
4
ad);
var user = context.Users.FirstOrDefault(e
‘ntps:ifcheatshectseries.owasp.oricheatsheets/DotNet_Securty_Cheat_Sheethtml 1923972322, 07 AM DotNet Securty - OWASP Cheat Sheet Series
// Establish user has right to edit the details
if (user.Id != _userIdentity .GetUserl6())
{
HandieErrorinfo error = new HandleErrorinfo(
new Exception(“INFO: You do not have permission to edit these details"));
return View(*Error”, error);
)
return View("Edit", new UserViewNodel (user) ;
+
More information can be found nere for Insecure Direct Object Reference.
A6 Security Misconfiguration
Debug and Stack Trace
Ensure debug and trace are off in production. This can be enforced using web.config transforms:
DO NOT: Use default passwords
DO: (When using TLS) Redirect a request made over Hitp tohtips:
eg Globalasaxcs
protected void Application BeginRequest()
4
#2 DEBUG
// SECURE: Ensure any request is returned over SSL/TLS in production
if (4Request.IsLocal @& !Context Request .IsSecureConnection) {
var redirect = Context Request ,Url.ToString(),
-ToLower (CultureInfo.currentCulture)
sReplace("http:", "https:");
Response Redirect(redirect) ;
}
endif
eg Startupcsin the Configure()
app.UselttpsRedirection();
Cross-site request forgery
‘ntps:ifcheatshectseries.owasp.oricheatsheets/DotNet_Securty_Cheat_Sheethtml 1439123/22, 9:07 AM DotNet Securty - OWASP Cheat Sheet Series
DO NOT: Send sensitive data without validating AntiForgery-Tokens (NET / NET Core).
DO: Send the anti forgery token with every POST/PUT request:
USING NET FRAMEWORK
using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id =
“LogoutForm”,
@class = “pull-right" }))
4
Html .AntiForgeryToken()
}
‘Then validete it at the method or preferably the controller level:
[HttpPost]
[ValidateantiforgeryToken]
public ActionResult LogOff()
Make sure the tokens are remaved completely for invalidation on logout.
///
//] SECURE: Remove any remaining cookies including Anti-CSRF cookie
//1
public void RemoveAntiForgeryCookie(Gontroller controller)
4
stringl] allCookies = controller Request .Cookies.AlIKeys;
foreach (string cookie in aliCookies)
4
if (controller.Response.Cookies[cookie] != null &
cookie = "__RequestVerificetionToke
{
cont roller .Response.Cookies[cookie].Expires = DateTime.Now.AddDays(-1) ;
}
+
+
USING NET CORE 2.0 OR LATER
‘ntps:ifcheatshectseries.owasp.oricheatsheets/DotNet_Securty_Cheat_Sheethtml 1923972322, 07 AM DotNet Securty - OWASP Cheat Sheet Series
Starting with NET Core 20itis possible to automatically generate and verify the antiforgery token.
I youare using tag:helpers, which is the default for most web project templates, then ll forms will
‘automatically send the anti-forgery token. You can check f tag-helpers are enabled by checking if
yourmain _Viewinports.cshtnl file contains:
@addTagHelper *, Microsoft.AspNetCore.Mvc. TagHelpers.
THtrlHelper .SeginForm also sends anti-forgery-tokens automatically.
Unless you ate usingtag-helpers or THtmHelper .BeginFerm You must use the requisite helper on
formsas seen here: