Welcome to the Puma Scan rules documentation! Your guide to secure software development in the .NET Framework.
The Puma rules attempt to be as accurate as possible, but please understand that false positives and false negatives frequently happen in static analysis. We are always working to improve the quality and accuracy of our rulesets. Please report issues and feature requests (including an example code snippet and data flow) to us at support [at] pumascan [dot] com.
Security misconfiguration rules are run at the end of a compilation against the following file types:
During the configuration analysis phase, Puma Scan does the following:
Puma Scan performs a Web.config transform using the Web.Release.config file to generate a production configuration before analysis.
See the User Guide to find out how to configure the production transform file. Pro Version Only
Security warnings are added to Visual Studio’s Error List
JSON Web Tokens (JWT) payloads that do not have an Expiration Time (exp) will never expire, which allows an attacker to indefinitely replay a compromised token. Web service APIs relying on JSON Web Tokens (JWT) for authentication and authorization must enforce token expiration by requiring and validating the Expiration Time (exp) claim.
In ASP.NET Core, configure the Authentication service’s JwtBearer options to require to require the exp claim and validate the token’s lifetime:
RequireExpirationTime: Requires tokens to have the ‘exp’ claim.
ValidateLifetime: Requires the token’s lifetime to be validated.
CWE:
CWE-613: Insufficient Session Expiration
Secure Code Warrior Training
References:
https://cheatsheets.pragmaticwebsecurity.com/cheatsheets/jwt.pdf
https://tools.ietf.org/html/rfc7519#section-4.1.4
https://docs.microsoft.com/en-us/dotnet/api/microsoft.identitymodel.tokens.tokenvalidationparameters
Insecure Code: The following example shows the TokenValidationParameters RequireExpirationTime and ValidateLifetime properties set to false.
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
[...]
RequireExpirationTime = false,
ValidateLifetime = false,
};
});
Secure Code: Configure the TokenValidationParameters RequireExpirationTime and ValidateLifetime properties to true.
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
[...]
RequireExpirationTime = true,
ValidateLifetime = true,
};
});
Disabling LDAP Authentication configures insecure connections to the backend LDAP provider. Using the DirectoryEntry AuthenticationType property’s Anonymous or None option allows an anonymous or basic authentication connection to the LDAP provider.
Set the the DirectoryEntry AuthenticationType property to Secure, which requests Kerberos authentication under the security context of the calling thread or as a provider username and password.
CWE:
CWE-287: Improper Authentication
Secure Code Warrior Training
References:
https://docs.microsoft.com/en-us/dotnet/api/system.directoryservices.authenticationtypes
Insecure Code: The following example shows an DirectoryEntry with the AuthenticationType set to Anonymous, which means no authentication is performed.
DirectoryEntry entry = new DirectoryEntry("LDAP://DC=PUMA}, DC=COM/");
entry.AuthenticationType = AuthenticationTypes.Anonymous;
Secure Code: Set the AuthenticationType set to Secure, which requests Kerberos authentication under the security context of the calling thread or as a provider username and password.
DirectoryEntry entry = new DirectoryEntry("LDAP://DC=PUMA}, DC=COM/");
entry.AuthenticationType = AuthenticationTypes.Secure;
Cross-Site Scripting rules are run against the application source code and view markup files (.cshtml, .aspx, .ascx).
Data is written to the browser using the HttpResponse.Write method. This can result in Cross-Site Scripting (XSS) vulnerabilities if the data source is considered untrusted or dynamic (request parameters, database, web service, etc.).
Ensure all dynamic data is properly encoded in the browser. Consider using the AntiXssEncoder library to neutralize dangerous data before writing it the browser. For example, the HtmlEncode method should be used to encode data displayed in an HTML context.
CWE:
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/1463ysyw(v=vs.110).aspx
Insecure Code: The following example shows the Raw Response.Write method writing a dynamic request parameter into HTML without HTML encoding.
string user = Request["user"]?.ToString();
Response.Write("We're sorry" + user + "but that contest is not valid. Please click your back button and try again.");
Secure Code: Ensure HTML encoding is applied prior to writing dynamic data into the browser’s HTML context.
string user = Request["user"]?.ToString();
Response.Write("We're sorry" + Encoder.HtmlEncode(user) + "but that contest is not valid. Please click your back button and try again.");
Data is written to the browser using a raw Razor helper method: @Html.Raw(Model.Variable). This can result in Cross-Site Scripting (XSS) vulnerabilities if the data source is considered untrusted or dynamic (request parameters, database, web service, etc.).
Instead of using the raw Razor helper method, use a Razor helper that performs automatic HTML encoding before writing it to the browser.
CWE:
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Secure Code Warrior Training
References:
https://software-security.sans.org/developer-how-to/developer-guide-xss
Insecure Code: The following example shows the Raw Razor helper method writing a dynamic value to the view.
<div class="loginDisplay">
@Html.Raw(string.Format("Welcome <span class=\"bold\">{0}</span>!", Model.UserName))
</div>
Secure Code: Replace the Raw Razor method with a Razor helper method that automatically HTML encodes the output data.
<div class="loginDisplay">
Welcome <span class="bold">@Model.UserName</span>!
</div>
Data is written to the browser using the raw WriteLiteral method. This can result in Cross-Site Scripting (XSS) vulnerabilities if the data source is considered untrusted or dynamic (request parameters, database, web service, etc.).
Instead of using the raw WriteLiteral method, use a Razor helper that performs automatic HTML encoding before writing it to the browser.
CWE:
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/system.web.webpages.webpagebase.writeliteral(v=vs.111).aspx
https://msdn.microsoft.com/en-us/library/system.web.webpages.html.htmlhelper_methods(v=vs.111).aspx
Insecure Code: The following example shows the Raw WriteLiteral method writing a dynamic value to the view.
<div class="loginDisplay">
@{
WriteLiteral(string.Format("Welcome <span class=\"bold\">{0}</span>!", Model.UserName));
}
</div>
Secure Code: Replace the WriteLiteral method with a Razor helper method that automatically HTML encodes the output data.
<div class="loginDisplay">
Welcome <span class="bold">@Model.UserName</span>!
</div>
Data is written to the browser using the Element.innerHTML property. Data bound directly to an Element.innerHTML property will be written to the browser unencoded potentially resulting in Cross-Site Scripting (XSS) vulnerabilities if the data source is considered untrusted or dynamic (request parameters, database, web service, etc.).
Bind user provided data to Node.textContext so the browser renders the content as text. Alternatively, ensure data is properly encoded prior to assigning to an Element.innerHTML property.
CWE:
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Secure Code Warrior Training
References:
https://capec.mitre.org/data/definitions/18.html
https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML
https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html
Insecure Code: Data will be parsed as HTML and the onerror function executed when the image’s source causes an error.
let executableXss = "<img src='xx' onerror='alert(\"XSS Performed\")'>"
element.innerHTML = executableXss
Secure Code: Data will be rendered as raw text, not parsed as HTML, and the onerror function will not be executed.
let executableXss = "<img src='xx' onerror='alert(\"XSS Performed\")'>"
element.textContent = executableXss
React’s ‘dangerouslySetInnerHTML’ allows data to be directly bound to an element’s innerHTML property. Data bound directly to an Element.innerHTML property will be written to the browser unencoded potentially resulting in Cross-Site Scripting (XSS) vulnerabilities if the data source is considered untrusted or dynamic (request parameters, database, web service, etc.).
Use the recommended data binding method of “{ data }” within HTML tags. However, if you have to bind data to innerHTML, ensure the data is from a trusted source, it cannot be manipulated in transit, and potentially executable code is rendered harmless. Alternatively, ensure data is properly encoded prior to binding to the ‘dangerouslySetInnerHTML’ property.
CWE:
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Secure Code Warrior Training
References:
https://capec.mitre.org/data/definitions/18.html
https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html
Insecure Code:
function renderUserComment(userComment) {
return {__html: userComment};
}
function CommentComponent() {
return '<div><p dangerouslySetInnerHTML={renderUserComment()} />';
}
Secure Code:
function CommentComponent() {
return '<div><p>{userComment}</p>';
}
The ‘bypassSecurityTrust’ family of functions exist to allow developers to circumvent Angular’s built-in sanitization functions. Data passed to the ‘bypassSecurityTrust’ family of functions will be written to the browser unencoded potentially exposing Angular applications to DOM based Cross-Site Scripting attacks.
Evaluate each use of the ‘bypassSecurityTrust’ function and determine if absolutely necessary. If these functions must be used, ensure the data being passed into them poses no security risk. The following methods are included in the ‘bypassSecurityTrust’ family:
CWE:
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Secure Code Warrior Training
References:
https://angular.io/api/platform-browser/DomSanitizer#security-risk
https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html
Insecure Code: The following example shows a user provided URL being allowed to bypass Angular’s security model. Allowing user provided content to circumvent security in this way exposes the application to potential XSS attacks.
comments: Comment[] = [];
constructor(private commentService: CommentService, private sanitizer: DomSanitizer) { }
loadComment(): void {
this.commentService.getComments()
.subscribe(comments => {
...
// Do not allow Angular to sanitize this URL
let externalUrl = this.sanitizer.bypassSecurityTrustUrl(comment.url);
comment.url = externalUrl;
this.comments.push(comment);
...
});
}
Secure Code: Allow Angular’s built-in sanitization model to safely encode user provided data. If you must allow untrusted user content to bypass security, ensure adequate precautions are taken to minimize potential damage.
comments: Comment[] = [];
constructor(private commentService: CommentService, private sanitizer: DomSanitizer) { }
loadComment(): void {
this.commentService.getComments()
.subscribe(comments => this.comments = comment);
}
Weak cryptography can allow attackers to perform a variety of cryptanalysis attacks and compromise the confidentially and integrity of encrypted and / or hashed data.
The DES, TripleDES, and RC2 classes use weak encryption algorithms and not considered secure for protecting sensitive information.
Use the AesManaged or AesCryptoServiceProvider algorithm (aka Rijndael) for symmetric encryption operations.
CWE:
CWE-327: Use of a Broken or Risky Cryptographic Algorithm
Secure Code Warrior Training
References:
http://csrc.nist.gov/groups/ST/toolkit/block_ciphers.html
https://msdn.microsoft.com/en-us/library/system.security.cryptography.aesmanaged(v=vs.110).aspx
Insecure Code: The following example shows the DESCryptoServiceProvider algorithm being used to encrypt a sensitive piece of data.
using (MemoryStream mStream = new MemoryStream())
{
//Input bytes
byte[] inputBytes = Encoding.UTF8.GetBytes(plainText);
SymmetricAlgorithm alg = new DESCryptoServiceProvider();
//Set key and iv
alg.Key = GetKey();
alg.IV = GetIv();
//Create the crypto stream
CryptoStream cStream = new CryptoStream(mStream, alg.CreateEncryptor(), CryptoStreamMode.Write);
cStream.Write(inputBytes, 0, inputBytes.Length);
cStream.FlushFinalBlock();
cStream.Close();
//Get the output
output = mStream.ToArray();
//Close resources
mStream.Close();
alg.Clear();
}
Secure Code: Use the AesManaged algorithm for symmetric encryption.
using (MemoryStream mStream = new MemoryStream())
{
//Input bytes
byte[] inputBytes = Encoding.UTF8.GetBytes(plainText);
SymmetricAlgorithm alg = new AesManaged();
//Set key and iv
alg.Key = GetKey();
alg.IV = GetIv();
//Create the crypto stream
CryptoStream cStream = new CryptoStream(mStream, alg.CreateEncryptor(), CryptoStreamMode.Write);
cStream.Write(inputBytes, 0, inputBytes.Length);
cStream.FlushFinalBlock();
cStream.Close();
//Get the output
output = mStream.ToArray();
//Close resources
mStream.Close();
alg.Clear();
}
The MD5CryptoServiceProvider class uses the weak MD5 algorithm and is not an approved hashing algorithm.
Use the SHA256Managed (at least) preferably SHA512Managed for hashing operations.
This alone is not sufficient for password hashing, which requires a unique salt and an adaptive hashing algorithm / iterations. See the references below for more information on password hashing in .NET.
CWE:
CWE-327: Use of a Broken or Risky Cryptographic Algorithm
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/system.security.cryptography.sha256(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/system.security.cryptography.sha512(v=vs.110).aspx
https://blogs.dropbox.com/tech/2016/09/how-dropbox-securely-stores-your-passwords/
Insecure Code: The following example shows the MD5 algorithm hashing a piece of data.
HashAlgorithm hash = new MD5CryptoServiceProvider();
byte[] bytes = hash.ComputeHash(input);
Secure Code: Use SHA256Managed or SHA512Managed for hashing operations (note: this is not enough for storing passwords).
HashAlgorithm hash = new SHA512Managed();
byte[] bytes = hash.ComputeHash(input);
The SHA1 algorithm has known collision weaknesses and should not be used for security operations in new applications.
Use the SHA256Managed (at least) preferably SHA512Managed for hashing operations.
This alone is not sufficient for password hashing, which requires a unique salt and adaptive hashing algorithm. See the references below for more information on password hashing in .NET.
CWE:
CWE-327: Use of a Broken or Risky Cryptographic Algorithm
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/system.security.cryptography.sha1managed(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/system.security.cryptography.sha256(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/system.security.cryptography.sha512(v=vs.110).aspx
https://blogs.dropbox.com/tech/2016/09/how-dropbox-securely-stores-your-passwords/
Insecure Code: The following example shows the SHA1 algorithm hashing a piece of data.
HashAlgorithm hash = new SHA1CryptoServiceProvider();
byte[] bytes = hash.ComputeHash(input);
Secure Code: Use SHA256Managed or SHA512Managed for hashing operations (note: this is not enough for storing passwords).
HashAlgorithm hash = new SHA512Managed();
byte[] bytes = hash.ComputeHash(input);
System.Random is a statistical random number generator that does not generate sufficiently random values for use in a security context.
Generate values used in a security context (e.g., encryption keys, initialization vectors, random passwords, authentication tokens) using the System.Security.Cryptography.RNGCryptoServiceProvider.
CWE:
CWE-338: Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG)
Secure Code Warrior Training
References:
Insecure Code: The following example shows the System.Random algorithm creating a random value.
public static byte[] GenerateRandomBytes(int length)
{
var random = new Random();
byte[] bytes = new byte[length];
random.NextBytes(bytes);
return bytes;
}
Secure Code: Use the RNGCryptoServiceProvider class to create random values for use in security operations.
public static byte[] GenerateSecureRandomBytes(int length)
{
var random = new RNGCryptoServiceProvider();
byte[] bytes = new byte[length];
random.GetNonZeroBytes(bytes);
return bytes;
}
Due to advances in cryptanalysis attacks and cloud computing capabilities, the National Institute of Standards and Technology (NIST) deprecated 1024-bit RSA keys on January 1, 2011.
The Certificate Authority Browser Forum, along with the latest version of all browsers, currently mandates a minimum key size of 2048-bits for all RSA keys.
CWE:
CWE-326: Inadequate Encryption Strength
Secure Code Warrior Training
References:
https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57pt1r4.pdf
Insecure Code: The following example shows the RSACryptoServiceProvider initializing a 1024-bit key pair.
RSACryptoServiceProvider alg = new RSACryptoServiceProvider(1024);
Secure Code: Configure the RSACryptoServiceProvider with at least a 2048-bit key pair.
RSACryptoServiceProvider alg = new RSACryptoServiceProvider(2048);
Symmetric algorithms use a Cipher Mode to repeatedly apply a cryptographic transformation to multiple blocks of data. Weaknesses in the Cipher Mode can allow cryptographic attacks to compromise the integrity or confidentiality of data.
SEC0026 identifies usage of the weak Cipher Modes in symmetric encryption operations including CFB, CTS, ECB, and OFB. Each of these cipher modes contain cryptographic weaknesses. For example, Electronic Codebook (ECB) mode encrypts blocks individually without using an initialization vector, which fails to provide entropy for identical plaintext blocks being encrypted with the same encryption key. This can allow attackers to identify patterns and repetition in ciphertext, and may lead to the discovery of the original encryption key.
The .NET cryptography libraries do not contain support for the strongest Cipher Modes: Counter Mode (CTR) and Galois Counter Mode (GCM). Third-party encryption libraries, such as Bouncy Castle can be used instead of the native .NET cryptography libraries.
If a product is required to use the .NET cryptography libraries, use the CipherMode.CBC option for symmetric block cipher operations. However, the CipherMode.CBC mode is vulnerable to Padding Oracle attacks. See SEC0124 for details on Cipher Block Chaining (CBC) padding weaknesses and defenses.
CWE:
CWE-327: Use of a Broken or Risky Cryptographic Algorithm
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/system.security.cryptography.ciphermode(v=vs.110).aspx
Insecure Code: The following example shows the AES algorithm setting the Mode to the CipherMode.ECB option.
using (MemoryStream mStream = new MemoryStream())
{
//Input bytes
byte[] inputBytes = Encoding.UTF8.GetBytes(plainText);
SymmetricAlgorithm alg = Aes.Create();
alg.Mode = CipherMode.ECB;
//Set key and iv
alg.Key = GetKey();
alg.IV = GetIv();
//Create the crypto stream
CryptoStream cStream = new CryptoStream(mStream
, alg.CreateEncryptor()
, CryptoStreamMode.Write);
cStream.Write(inputBytes, 0, inputBytes.Length);
cStream.FlushFinalBlock();
cStream.Close();
//Get the output
output = mStream.ToArray();
//Close resources
mStream.Close();
alg.Clear();
}
Secure Code: Set the AES algorithm mode set to CipherMode.CBC option, perform an integrity check generate a unique initialization vector for each input.
//Perform integrity check on incoming data
string[] args = model.ProtectedData.Split('.');
byte[] ciphertext = Convert.FromBase64String(args[0]);
byte[] hmac = Convert.FromBase64String(args[1]);
HMACSHA256 hmac = new HMACSHA256(_KEY);
byte[] verification = hmac.ComputeHash(ciphertext);
if (!verification.SequenceEqual(hmac))
throw new ArgumentException("Invalid signature detected.");
using (MemoryStream mStream = new MemoryStream())
{
SymmetricAlgorithm alg = Aes.Create();
alg.Mode = CipherMode.CBC;
//Set key and iv
alg.Key = GetKey();
alg.IV = GetIv();
//Create the crypto stream
CryptoStream cStream = new CryptoStream(mStream
, alg.CreateDecryptor()
, CryptoStreamMode.Write);
cStream.Write(ciphertext, 0, inputBytes.Length);
cStream.FlushFinalBlock();
cStream.Close();
//Get the cleartext
byte[] cleartext = mStream.ToArray();
//Close resources
mStream.Close();
alg.Clear();
}
Padding Oracle attacks can occur in applications that decrypt ciphertext values without an integrity check. This is commonly identified when decrypting untrusted values from an HTTP request or web service. Applications that meet the following criteria are vulnerable to padding oracle attacks:
Data encryption uses a block cipher algorithm (e.g. 3DES or AES) in Cipher Block Chaining (CBC) mode.
Error handling responds differently (e.g. error message, error code, or response time) when given invalid ciphertext with valid padding and invalid ciphertext with invalid padding (aka a side channel attack).
Protecting against padding oracle attacks requires applications to verify the ciphertext’s integrity prior to decryption. To do this, create an HMAC of the ciphertext value with a private key and send both the ciphertext and HMAC values to the client. During decryption, read the ciphertext parameter, generate a new HMAC value, and compare the result to the original HMAC value. If the values HMAC match, proceed with decrypting the ciphertext. If the HMAC values do not match, respond with a consistent response code and error message to the client.
Alternatively, third-party encryption libraries provide support for stronger Cipher Modes: Counter Mode (CTR) and Galois Counter Mode (GCM), such as Bouncy Castle can be used instead of the native .NET cryptography libraries.
SEC0124 identifies usage of the CBC padding mode. It does not currently perform data flow analysis to see if the incoming bytes have been passed through an acceptable HMAC method to suppress finding. See the User Guide for details on creating false positive exceptions.
CWE:
CWE-347: Improper Verification of Cryptographic Signature
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/Testing_for_Padding_Oracle_(OTG-CRYPST-002)
https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.ciphermode
http://resources.infosecinstitute.com/padding-oracle-attack-2/
Insecure Code: The following example shows the AES algorithm decrypting an untrusted parameter using the CipherMode.CBC mode without an integrity check.
//Perform integrity check on incoming data
byte[] ciphertext = Convert.FromBase64String(model.ProtectedData);
using (MemoryStream mStream = new MemoryStream())
{
//Input bytes
byte[] inputBytes = Encoding.UTF8.GetBytes(plainText);
SymmetricAlgorithm alg = Aes.Create();
alg.Mode = CipherMode.CBC;
//Set key and iv
alg.Key = GetKey();
alg.IV = GetIv();
//Create the crypto stream
CryptoStream cStream = new CryptoStream(mStream
, alg.CreateEncryptor()
, CryptoStreamMode.Write);
cStream.Write(inputBytes, 0, inputBytes.Length);
cStream.FlushFinalBlock();
cStream.Close();
//Get the output
output = mStream.ToArray();
//Close resources
mStream.Close();
alg.Clear();
}
Secure Code: Set the AES algorithm mode set to CipherMode.CBC option and perform an integrity check on the incoming ciphertext.
//Perform integrity check on incoming data
string[] args = model.ProtectedData.Split('.');
byte[] ciphertext = Convert.FromBase64String(args[0]);
byte[] hmac = Convert.FromBase64String(args[1]);
HMACSHA256 hmac = new HMACSHA256(_KEY);
byte[] verification = hmac.ComputeHash(ciphertext);
if (!verification.SequenceEqual(hmac))
throw new ArgumentException("Invalid signature detected.");
using (MemoryStream mStream = new MemoryStream())
{
SymmetricAlgorithm alg = Aes.Create();
alg.Mode = CipherMode.CBC;
//Set key and iv
alg.Key = GetKey();
alg.IV = GetIv();
//Create the crypto stream
CryptoStream cStream = new CryptoStream(mStream
, alg.CreateDecryptor()
, CryptoStreamMode.Write);
cStream.Write(ciphertext, 0, inputBytes.Length);
cStream.FlushFinalBlock();
cStream.Close();
//Get the cleartext
byte[] cleartext = mStream.ToArray();
//Close resources
mStream.Close();
alg.Clear();
}
Similar to other platforms, .NET deserialization vulnerabilities occur when applications deserialize untrusted data. Without validation (e.g. HMAC signature validation), deserializing untrusted data can lead to application crashes, unauthorized access to resources, and remote code execution.
Deserializing untrusted data using vulnerable libraries can allow attackers to execute arbitrary code and perform denial of service attacks against the server.
SEC0029 covers over 25 .NET libraries vulnerable to deserialization attacks. The most commonly used libraries are as follows:
Avoid deserializing untrusted data (e.g. request parameters, web service parameters, data from external services) using the above dangerous methods. In cases where deserialization is required, ensure that the application performs signature validation (e.g. HMAC) before deserializing the data.
The SEC0029 analyzer currently looks for insecure function calls. Data flow analysis is not yet performed to determine if the binary content being parsed is actually controllable by an attacker.
CWE:
CWE-502: Deserialization of Untrusted Data
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization
https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf
https://docs.microsoft.com/en-us/dotnet/api/system.web.script.serialization.javascriptserializer
https://docs.microsoft.com/en-us/dotnet/api/system.web.ui.objectstateformatter
https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.netdatacontractserializer
https://docs.microsoft.com/en-us/dotnet/api/system.web.ui.losformatter
Insecure Code: The following example shows the BinaryFormatter Deserialize method deserializing a byte array without HMAC signature validation.
using (MemoryStream stream = new MemoryStream())
{
byte[] bytes = Convert.FromBase64String(model.UserData);
stream.Write(bytes, 0, bytes.Length);
BinaryFormatter formatter = new BinaryFormatter();
return (User)formatter.Deserialize(stream);
}
Secure Code: Ensure that the application performs signature validation (e.g. HMAC) before deserializing the data. This snippet assumes that the serialized data has been concatenated with the signature (joined using a ‘.’) and sent to the client.
//Validate user data signature
string[] args = model.UserData.Split('.');
byte[] userData = Convert.FromBase64String(args[0]);
byte[] hmac = Convert.FromBase64String(args[1]);
HMACSHA256 hmac = new HMACSHA256(_KEY);
byte[] verification = hmac.ComputeHash(userData);
if (!verification.SequenceEqual(hmac))
throw new ArgumentException("Invalid signature detected.");
//If valid, process the deserialization
using (MemoryStream stream = new MemoryStream())
{
byte[] bytes = Convert.FromBase64String(userData);
stream.Write(bytes, 0, bytes.Length);
BinaryFormatter formatter = new BinaryFormatter();
return (User)formatter.Deserialize(stream);
}
The Newtonsoft JSON DeserializeObject method can allow attackers to execute arbitrary code and perform denial of service attacks if the TypeNameHandling setting is set to a value other than None.
Validate incoming data with HMAC protection to ensure it has not been modified on the client. Explicitly set the TypeNameHandling setting to None (which is the default) to prevent JSON deserialization vulnerabilities.
CWE:
CWE-502: Deserialization of Untrusted Data
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization
http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_TypeNameHandling.htm
Insecure Code: The following example shows the model.UserData request parameter being deserialized with Newtonsoft JSON serialization TypeNameHandling enumeration set to All.
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.TypeNameHandling = TypeNameHandling.Auto;
return JsonConvert.DeserializeObject<User>(model.UserData, settings);
Secure Code: Validate incoming data with HMAC protection to ensure it has not been modified on the client. Explicitly set the TypeNameHandling setting to None (which is the default) to prevent JSON deserialization vulnerabilities.
//Validate user data signature
string[] args = json.Split('.');
byte[] userData = Convert.FromBase64String(args[0]);
byte[] hash = Convert.FromBase64String(args[1]);
HMACSHA256 hmac = new HMACSHA256(_KEY);
byte[] verification = hmac.ComputeHash(userData);
if (!verification.SequenceEqual(hash))
throw new ArgumentException("Invalid signature detected.");
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.TypeNameHandling = TypeNameHandling.None;
return JsonConvert.DeserializeObject<T>(Encoding.UTF8.GetString(userData), settings);
Injection rules run against the application source code and look for calls to insecure methods. The following injection patterns are supported:
Concatenating untrusted data into operating system commands can allow attackers to execute arbitrary commands against the server’s operating system.
Defending against command injection in the .NET ecosystem is more difficult than other injection categories because no special encoding method exists to approve safe characters and escape evil characters.
To prevent command injection, follow this pattern:
Does the user really need to directly control the fileName passed to this command? The answer is usually No. Consider moving the fileName values to server-side storage and look up the value using a non-injectable value such as a GUID, integer, etc. passed in from the request. For example, consider an application that allows the user to run two commands: calc.exe and process.exe.
Command Name | GUID |
---|---|
calc.exe | 06C67D8C-CAD5-4003-B065-1089CFF0D1E9 |
process.exe | A180A8AF-C667-4074-A768-C95F13819E2A |
Requests pass in a valid GUID and the application selects the associated process. If the GUID is not valid, throw an exception. This ensures that the user can only run a process that exists in your list of approved processes.
Validate incoming arguments against a strict list of approved values or characters only and reject everything else. Consider using the server-side lookup tables (as described above) for argument values as well. Avoid using string values whenever possible, instead opting for non-injectable data types (e.g. GUID, integer, date, decimal, etc.). If string values must be passed as an argument, then use regular expressions to restrict the characters to avoid special characters. For example: [A-za-z0-9]+
Reject the special characters shown to the right in Figure 1.
CWE:
CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/Top_10-2017_A1-Injection
https://msdn.microsoft.com/en-us/library/system.diagnostics.process.start(v=vs.110).aspx
Figure 1 The following characters are control characters in various shells (cmd, bash, etc.) and should be stripped from untrusted string values being passed to the fileName or arguments parameters.
& < > [ ] { } ^ = ; ! ' + , ` ~ [white space].
Insecure Code: The following example shows the model.FileName parameter being passed to the Process.Start method’s fileName parameter. This allows an attacker to execute arbitrary commands on the server.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Run(ProcessViewModel model)
{
Process p = Process.Start(model.FileName);
model.ExitCode = p.ExitCode;
return View(model);
}
Secure Code: Rather than allowing the user to control the file name directly, look up the fileName in a server-side collection. The following example verifies the file id against the command entries in a server-side configuration file before executing the command.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Run(ProcessViewModel model)
{
//Pull valid commands from the configuration file
List<Command> commands = GetCommands();
//Verify the command exists
Command c = commands.FirstOrDefault(i => i.Id == model.FileId);
if (c == null)
throw new ArgumentException("Invalid file name parameter");
Process p = Process.Start(c.FileName);
model.ExitCode = p.ExitCode;
return View(model);
}
Concatenating untrusted data into operating system commands can allow attackers to execute arbitrary commands against the server’s operating system.
Defending against command injection in the .NET ecosystem is more difficult than other injection categories because no special encoding method exists to allow safe characters and escape evil characters.
To prevent command injection, follow this pattern:
Does the user really need to directly control the fileName passed to this command? The answer is usually No. Consider moving the fileName values to server-side storage and look up the value using a non-injectable value such as a GUID, integer, etc. passed in from the request. For example, consider an application that allows the user to run two commands: calc.exe and process.exe.
Command Name | GUID |
---|---|
calc.exe | 06C67D8C-CAD5-4003-B065-1089CFF0D1E9 |
process.exe | A180A8AF-C667-4074-A768-C95F13819E2A |
Requests pass in a valid GUID and the application selects the associated process. If the GUID is not valid, throw an exception. This ensures that the user can only run a process that exists in your list of approved processes.
Validate incoming arguments against a strict list of approved values or characters and reject everything else. Consider using the server-side lookup tables (as described above) for argument values as well. Avoid using string values whenever possible, instead opting for non-injectable data types (e.g. GUID, integer, date, decimal, etc.). If string values must be passed as an argument, then use regular expressions to restrict the characters to avoid special characters. For example: [A-za-z0-9]+
Reject the special characters shown to the right in Figure 1.
CWE:
CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/Top_10-2017_A1-Injection
https://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo(v=vs.110).aspx
Figure 1 The following characters are control characters in various shells (cmd, bash, etc.) and should be stripped from untrusted string values being passed to the fileName or arguments parameters.
& < > [ ] { } ^ = ; ! ' + , ` ~ [white space].
Insecure Code: The following example shows the model.FileName parameter being passed to the ProcessStartInfo constructor’s fileName parameter. This allows an attacker to execute arbitrary commands on the server.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Run(ProcessViewModel model)
{
ProcessStartInfo info = new ProcessStartInfo()
{
FileName = model.FileName,
};
Process p = Process.Start(info);
model.ExitCode = p.ExitCode;
return View(model);
}
Secure Code: Rather than allowing the user to control the file name directly, look up the fileName in a server-side collection. The following example verifies the file id against the command entries in a server-side configuration file before executing the command.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Run(ProcessViewModel model)
{
//Pull valid commands from the configuration file
List<Command> commands = GetCommands();
//Verify the command exists
Command c = commands.FirstOrDefault(i => i.Id == model.FileId);
if (c == null)
throw new ArgumentException("Invalid file name parameter");
ProcessStartInfo info = new ProcessStartInfo()
{
FileName = c.FileName,
};
Process p = Process.Start(info);
model.ExitCode = p.ExitCode;
return View(model);
}
XML External Entity (XXE) vulnerabilities occur when applications process untrusted XML data without disabling external entities and DTD processing. Processing untrusted XML data with a vulnerable parser can allow attackers to extract data from the server, perform denial of service attacks, and in some cases gain remote code execution.
.NET Framework v4.5.1 (And Older)
The XPathDocument class is vulnerable to XXE attacks when loading XML from a file URI, TextReader, or Stream. The only secure way to parse XML using the XPathDocument class in .NET Framework versions prior to 4.5.2 is to load the content using an XmlReader object, which by default does not have external entities enabled.
.NET Framework v4.5.2 (And Newer)
The XPathDocument class was patched to securely parse XML content. Applications targeting .NET 4.5.2 and greater are not vulnerable (by default) to XXE attacks when using the XPathDocument class.
The SEC0035 analyzer looks for usage of the XPathDocument class in projects targeting .NET Framework 4.5.1 and older. Diagnostic warnings will be raised (regardless of the source XML data) if the constructor is loading XML data from a file URI, TextReader, or Stream.
CWE:
CWE-611: Improper Restriction of XML External Entity Reference
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)
https://docs.microsoft.com/en-us/dotnet/api/system.xml.xpath.xpathdocument
https://www.jardinesoftware.net/2016/09/12/xxe-in-net-and-xpathdocument/
Insecure Code: The following example shows the XPathDocument loading XML content using a file URI stored in the model.FilePath variable:
XPathDocument xmlDoc = new XPathDocument(model.FilePath);
XPathNavigator nav = xmlDoc.CreateNavigator();
Secure Code: Load the XML content into an XmlReader object first. Then, pass the XmlReader into the XPathDocument constructor.
XmlReader reader = XmlReader.Create(model.FilePath);
XPathDocument xmlDoc = new XPathDocument(reader);
XPathNavigator nav = xmlDoc.CreateNavigator();
XML External Entity (XXE) vulnerabilities occur when applications process untrusted XML data without disabling external entities and DTD processing. Processing untrusted XML data with a vulnerable parser can allow attackers to extract data from the server, perform denial of service attacks, and in some cases gain remote code execution.
The XmlReaderSettings and XmlTextReader classes are vulnerable to XXE attacks when setting the DtdProcessing property to DtdProcessing.Parse or the ProhibitDtd property to false.
To prevent XmlReader XXE attacks, avoid using the deprecated ProhibitDtd property. Set the DtdProcessing property to DtdProcessing.Ignore or DtdProcessing.Prohibit.
The SEC0036 analyzer currently looks for insecure XmlReaderSettings and XmlTextReader configuration. Data flow analysis is not performed to determine if the XML content being parsed is actually controllable by an attacker.
CWE:
CWE-611: Improper Restriction of XML External Entity Reference
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)
https://www.jardinesoftware.net/2016/05/26/xxe-and-net/
https://docs.microsoft.com/en-us/dotnet/api/system.xml.xmlreadersettings.dtdprocessing
https://docs.microsoft.com/en-us/dotnet/api/system.xml.xmlreadersettings.prohibitdtd
https://docs.microsoft.com/en-us/dotnet/api/system.xml.xmltextreader.dtdprocessing
https://docs.microsoft.com/en-us/dotnet/api/system.xml.xmltextreader.prohibitdtd
Insecure Code: The following example shows the XmlReaderSettings DtdProcessing property set to Parse, which allows external entities to be parsed by the XmlReader:
XmlReaderSettings rs = new XmlReaderSettings
{
DtdProcessing = DtdProcessing.Parse,
};
XmlReader reader = XmlReader.Create("evil.xml", rs);
while (reader.Read())
Secure Code: Configure the XmlReaderSettings to Prohibit parsing external XML entities.
XmlReaderSettings rs = new XmlReaderSettings
{
DtdProcessing = DtdProcessing.Prohibit,
};
XmlReader reader = XmlReader.Create("evil.xml", rs);
while (reader.Read())
XML External Entity (XXE) vulnerabilities occur when applications process untrusted XML data without disabling external entities and DTD processing. Processing untrusted XML data with a vulnerable parser can allow attackers to extract data from the server, perform denial of service attacks, and in some cases gain remote code execution.
The XmlDocument class is vulnerable to XXE attacks when setting the XmlResolver property to resolve external entities.
To prevent XmlDocument XXE attacks, set the XmlResolver property to null.
The SEC0037 analyzer currently looks for insecure XmlDocument configuration. Data flow analysis is not performed to determine if the XML content being parsed is actually controllable by an attacker.
CWE:
CWE-611: Improper Restriction of XML External Entity Reference
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)
https://www.jardinesoftware.net/2016/05/26/xxe-and-net/
https://docs.microsoft.com/en-us/dotnet/api/system.xml.xmldocument.xmlresolver
Insecure Code: The following example shows the XmlDocument XmlResolver property set to resolve external entities:
XmlUrlResolver resolver = new XmlUrlResolver();
resolver.Credentials = CredentialCache.DefaultCredentials;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.XmlResolver = resolver;
xmlDoc.LoadXml(xml);
Secure Code: Configure the XmlDocument XmlResolver property to null to prevent resolving external XML entities.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.XmlResolver = null;
xmlDoc.LoadXml(xml);
Concatenating untrusted data into a dynamic SQL string and calling vulnerable LINQ methods can allow SQL Injection:
To ensure calls to vulnerable LINQ methods are parameterized, pass parameters into the statement using the method’s second argument: params object[] parameters.
CWE:
CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/Top_10-2017_A1-Injection
https://msdn.microsoft.com/en-us/library/bb361109(v=vs.110).aspx
Insecure Code: The following example shows dynamic SQL passed to the ExecuteQuery LINQ method.
using (DbDataContext context = new DbDataContext())
{
string q = "SELECT Name from Items where ProductCode = " + model.ProductCode;
name = context.ExecuteQuery<string>(q).SingleOrDefault().ToString();
}
Secure Code: Call the overloaded ExecuteQuery method that accepts a list of parameters in the second argument.
using (DbDataContext context = new DbDataContext())
{
string q = "SELECT Name from Items where ProductCode = {0}";
name = context.ExecuteQuery<string>(q, model.ProductCode).SingleOrDefault().ToString();
}
ADO.NET classes allow applications to communicate directly to a backend database without using an Object Relational Mapping (ORM) framework. SEC0107 identifies the following classes allowing dynamic SQL statements to be constructed and executed:
Ensure that calls to these methods do not concatenate untrusted data into dynamic SQL statements sent to the CommandText. Use parameter placeholders or stored procedures to prevent SQL Injection attacks.
CWE:
CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/Top_10-2017_A1-Injection
https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand(v=vs.110).aspx
https://docs.microsoft.com/en-us/dotnet/api/microsoft.data.sqlite.sqlitecommand
https://docs.microsoft.com/en-us/dotnet/api/system.data.oledb.oledbcommand
https://docs.microsoft.com/en-us/dotnet/api/system.data.odbc.odbccommand
Insecure Code: The following example shows a snippet concatenating a request parameter into a dynamic SQL statement. The statement is executed using the ExecuteScalar method.
SqlCommand cmd = new SqlCommand("select count(*) from Users where UserName = '" + model.UserName + "'", cn);
string result = cmd.ExecuteScalar().ToString();
Secure Code: Parameterize the query using the standard ADO.NET placeholders and set the parameter value.
SqlCommand cmd = new SqlCommand("select count(*) from Users where UserName = @UserName", cn);
SqlParameter parm = new SqlParameter("@UserName", NVarChar);
parm.Value = model.UserName;
cmd.Parameters.Add(parm);
string result = cmd.ExecuteScalar().ToString();
Concatenating untrusted data into a dynamic SQL string and calling vulnerable Entity Framework (EF) methods can allow SQL Injection:
To ensure calls to vulnerable EF methods are parameterized, pass parameters into the statement using the method’s second argument: params object[] parameters.
CWE:
CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/Top_10-2017_A1-Injection
https://msdn.microsoft.com/en-us/library/system.data.entity.database(v=vs.113).aspx
Insecure Code: The following example shows dynamic SQL passed to the ExecuteSqlCommand Entity Database method.
using (DbDataContext context = new DbDataContext())
{
string q = "DELETE FROM Items WHERE ProductCode = '" + model.ProductCode + "'";
context.Database.ExecuteSqlCommand(q);
}
Secure Code: Call the overloaded ExecuteSqlCommand method that accepts a list of parameters in the second argument.
using (DbDataContext context = new DbDataContext())
{
string q = "DELETE FROM Items WHERE ProductCode = @productCode";
context.Database.ExecuteSqlCommand(q, model.ProductCode);
}
Concatenating untrusted data into a dynamic SQL string and calling vulnerable NHibernate Framework methods can allow SQL Injection. To ensure calls to vulnerable NHibernate Framework methods are parameterized, pass positional or named parameters in the statement. The following NHibernate methods allow for raw SQL queries to be executed:
To ensure calls to vulnerable NHibernate methods are parameterized, use named parameters in the raw SQL query. Then, set the named parameter values when executing the query.
CWE:
CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/Top_10-2017_A1-Injection
https://nhibernate.info/doc/nhibernate-reference/querysql.html
Insecure Code: The following example shows a request parameter being concatenated into a dynamic SQL statement, which is executed by the NHibernate CreateQuery method.
string q = "SELECT * FROM Items WHERE ProductCode = '" + model.ProductCode + "'";
var cfg = new Configuration();
ISessionFactory sessions = cfg.BuildSessionFactory();
ISession session = sessions.OpenSession();
var query = session.CreateQuery(q);
var product = query.List<Product>().FirstOrDefault();
Secure Code: Use NHibernate named parameters to prevent SQL Injection. The following examples shows the :productCode bind parameter
string q = "SELECT * FROM Items WHERE ProductCode = :productCode";
var cfg = new Configuration();
ISessionFactory sessions = cfg.BuildSessionFactory();
ISession session = sessions.OpenSession();
var query = session.CreateQuery(q);
var product = query
.SetString("productCode", model.ProductCode)
.List<Product>().FirstOrDefault();
LDAP Injection vulnerabilities occur when untrusted data is concatenated into a LDAP Path or Filter expression without properly escaping control characters. This can allow attackers to change the meaning of an LDAP query and gain access to resources for which they are not authorized.
Fixing the LDAP Injection Directory Entry vulnerability requires untrusted data to be encoded using the appropriate Web Protection Library (aka AntiXSS) LDAP encoding method:
CWE:
CWE-90: Improper Neutralization of Special Elements used in an LDAP Query ('LDAP Injection')
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/Top_10-2017_A1-Injection
https://msdn.microsoft.com/en-us/library/system.directoryservices.directoryentry(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/system.directoryservices.directorysearcher(v=vs.110).aspx
Insecure Code: The following example shows untrusted data being concatenated into directory entry constructor path without escaping LDAP control characters.
DirectoryEntry entry = new DirectoryEntry(string.Format("LDAP://DC={0}, DC=COM/", model.Domain));
DirectorySearcher searcher = new DirectorySearcher(entry);
searcher.SearchScope = SearchScope.Subtree;
searcher.Filter = "(name={BobbyTables})";
SearchResultCollection resultCollection = searcher.FindAll();
Secure Code: Encode untrusted data passed to the DirectoryEntry path argument with the Web Protection Library’s (aka AntiXSS) LdapDistinguishedNameEncode method.
DirectoryEntry entry = new DirectoryEntry(string.Format("LDAP://DC={0}, DC=COM/", Encoder.LdapDistinguishedNameEncode(model.Domain));
DirectorySearcher searcher = new DirectorySearcher(entry);
searcher.SearchScope = SearchScope.Subtree;
searcher.Filter = "(name={BobbyTables})";
SearchResultCollection resultCollection = searcher.FindAll();
LDAP Injection vulnerabilities occur when untrusted data is concatenated into a LDAP Path or Filter expression without properly escaping control characters. This can allow attackers to change the meaning of an LDAP query and gain access to resources for which they are not authorized.
Fixing the LDAP Injection Path Assignment vulnerability requires untrusted data to be encoded using the appropriate Web Protection Library (aka AntiXSS) LDAP encoding method:
CWE:
CWE-90: Improper Neutralization of Special Elements used in an LDAP Query ('LDAP Injection')
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/Top_10-2017_A1-Injection
https://msdn.microsoft.com/en-us/library/system.directoryservices.directoryentry(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/system.directoryservices.directorysearcher(v=vs.110).aspx]
Insecure Code: The following example shows untrusted data being concatenated into the DirectoryEntry Path property without escaping LDAP control characters.
DirectoryEntry entry = new DirectoryEntry();
entry.Path = string.Format("LDAP://DC={0},DC=COM,CN=Users", model.Domain);
entry.Username = model.UserName;
entry.Password = model.Password;
DirectorySearcher searcher = new DirectorySearcher(entry);
searcher.SearchScope = SearchScope.Subtree;
searcher.Filter = $"(samaccountname=DOMAIN\\BobbyTables)";
SearchResult result = searcher.FindOne();
Secure Code: Encode untrusted data passed to the DirectoryEntry.Path property with the Web Protection Library’s (aka AntiXSS) LdapDistinguishedNameEncode method.
DirectoryEntry entry = new DirectoryEntry();
entry.Path = string.Format("LDAP://DC={0},DC=COM,CN=Users", Encoder.LdapDistinguishedNameEncode(model.Domain));
entry.Username = model.UserName;
entry.Password = model.Password;
DirectorySearcher searcher = new DirectorySearcher(entry);
searcher.SearchScope = SearchScope.Subtree;
searcher.Filter = $"(samaccountname=DOMAIN\\BobbyTables)";
SearchResult result = searcher.FindOne();
LDAP Injection vulnerabilities occur when untrusted data is concatenated into a LDAP Path or Filter expression without properly escaping control characters. This can allow attackers to change the meaning of an LDAP query and gain access to resources for which they are not authorized.
Fixing the LDAP Injection Directory Searcher vulnerability requires untrusted data to be encoded using the Web Protection Library (aka AntiXSS) LDAP encoding method:
CWE:
CWE-90: Improper Neutralization of Special Elements used in an LDAP Query ('LDAP Injection')
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/Top_10-2017_A1-Injection
https://msdn.microsoft.com/en-us/library/system.directoryservices.directoryentry(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/system.directoryservices.directorysearcher(v=vs.110).aspx
Insecure Code: The following example shows untrusted data being concatenated into directory searcher constructor’s Filter property without escaping LDAP control characters.
DirectoryEntry entry = new DirectoryEntry("LDAP://DC=example.com, DC=COM/");
DirectorySearcher searcher = new DirectorySearcher(entry, string.Format("(name={0})", model.UserName);
searcher.SearchScope = SearchScope.Subtree;
SearchResultCollection resultCollection = searcher.FindAll();
Secure Code: Encode untrusted data passed to the DirectorySearcher Filter argument with the Web Protection Library’s (aka AntiXSS) LdapFilterEncode method.
DirectoryEntry entry = new DirectoryEntry("LDAP://DC=example.com, DC=COM/");
DirectorySearcher searcher = new DirectorySearcher(entry, string.Format("(name={0})", Encoder.LdapFilterEncode(model.UserName)));
searcher.SearchScope = SearchScope.Subtree;
SearchResultCollection resultCollection = searcher.FindAll();
LDAP Injection vulnerabilities occur when untrusted data is concatenated into a LDAP Path or Filter expression without properly escaping control characters. This can allow attackers to change the meaning of an LDAP query and gain access to resources for which they are not authorized.
Fixing the LDAP Injection Filter Assignment vulnerability requires untrusted data to be encoded using the Web Protection Library (aka AntiXSS) LDAP encoding method:
CWE:
CWE-90: Improper Neutralization of Special Elements used in an LDAP Query ('LDAP Injection')
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/Top_10-2017_A1-Injection
https://msdn.microsoft.com/en-us/library/system.directoryservices.directoryentry(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/system.directoryservices.directorysearcher(v=vs.110).aspx
Insecure Code: The following example shows untrusted data being concatenated into the DirectorySearcher Filter property without escaping LDAP control characters.
DirectoryEntry entry = new DirectoryEntry("LDAP://DC=example.com, DC=COM");
DirectorySearcher searcher = new DirectorySearcher(entry);
searcher.SearchScope = SearchScope.Subtree;
searcher.Filter = string.Format("(name={0})", model.UserName);
SearchResultCollection resultCollection = searcher.FindAll();
Secure Code: Encode untrusted data passed to the DirectorySearcher.Filter property with the Web Protection Library’s (aka AntiXSS) LdapFilterEncode method.
DirectoryEntry entry = new DirectoryEntry("LDAP://DC=example.com, DC=COM");
DirectorySearcher searcher = new DirectorySearcher(entry);
searcher.SearchScope = SearchScope.Subtree;
searcher.Filter = string.Format("(name={0})", Encoder.LdapFilterEncode(model.UserName));
SearchResultCollection resultCollection = searcher.FindAll();
Concatenating untrusted data into XPath queries allow attackers to change the meaning of the XPath query. The following XPath methods allow for raw queries to be executed:
.NET does not provide a built in library for parameterizing XPath queries. To prevent XPath Injection, ensure dynamic values are sanitized with strong input validation. Common methods include converting untrusted data to a strongly typed object (e.g. Int, Decimal, DateTime, etc.) or performing regular expression validation to restrict the characters (e.g. [A-za-z0-9]+).
For this reason, Puma Scan does not have a default cleanse method that allows SEC0127 findings to be eliminated. To remove a SEC0127 finding, register a Custom Cleanse Method that identifies your approved validation method for preventing XPath vulnerabilities.
CWE:
CWE-643: Improper Neutralization of Data within XPath Expressions ('XPath Injection')
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/XPATH_Injection
https://docs.microsoft.com/en-us/dotnet/api/system.xml.xmlnode.selectnodes
https://docs.microsoft.com/en-us/dotnet/api/system.xml.xmlnode.selectsinglenode
Insecure Code: The following example shows an XPath query against a backend XML user store. The XPath query concatenates the model.UserName request parameter into the query.
public IActionResult Post(Model model)
{
var doc = new XmlDocument { XmlResolver = null };
doc.Load(configuration["UserXmlPath"]);
var results = doc.SelectNodes("/Users/User[id='" + model.UserName + "']");
//Process login
[...]
return View();
}
Secure Code: Before
public IActionResult Post(Model model)
{
var userName = model.UserName;
if (!Regex.IsMatch(userName, @"[A-za-z0-9]+"))
{
throw new ArgumentException("Invalid username parameter.");
}
var doc = new XmlDocument { XmlResolver = null };
doc.Load(configuration["UserXmlPath"]);
var results = doc.SelectNodes("/Users/User[id='" + userName + "']");
//Process login
[...]
return View();
}
The ‘eval(string)’ function evaluates the contents of the string parameter as an expression, statement, or a sequence of statements exposing an application to arbitrary code execution. Common uses of the ‘eval()’ function are:
To evaluate JSON use the ‘JSON.parse()’ function which will throw an error if the object being parsed is not valid JSON thereby preventing malicious code discuised as JSON. Allowing users to input executable code is not recommended.
CWE:
CWE-95: Improper Neutralization of Directives in Dynamically Evaluated Code ('Eval Injection')
Secure Code Warrior Training
References:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
Insecure Code: The following example shows user provided data being passed to eval. The data does bad things.
function parsePayload(payload) {
const parsedPayload = eval(payload);
return parsedPayload;
}
Secure Code:
'use strict'
function parsePayload(payload) {
const parsedPayload = JSON.parse(payload);
return parsedPayload;
}
The ‘setTimeout()’ method allows executable code in the form of a string to be passed as the first parameter exposing an application to arbitrary code execution. This is usually done when dynamically creating a function and concatinating the arguments together as a string. The function will interpret and execute the code similar to ‘eval()’. As with ‘eval()’, this approach makes the function susceptible to command injection.
Avoid dynamically building functions as strings and instead use callbacks and declared functions.
CWE:
CWE-94: Improper Control of Generation of Code ('Code Injection')
Secure Code Warrior Training
References:
Insecure Code: Executable code as a string, depending on how its handled, can be subject to command injection.
var dynamiclyBuildFunction = 'function(countLength) {' +
'for(i = 0; i < countLength; i++) {' +
'console.log(i);' +
'injectedMaliciousCode' +
'}}'
setTimeout(dynamiclyBuildFunction(9999), 2000);
Secure Code: Function using business logic to …
const longRunningFunctionexample = function(countLength) {
// Business logic
const resultOfLogic = console.log(input);
for(i = 0; i < countLength; i++) {
resultOfLogic(i);
}
}
setTimeout(longRunningFunctionexample(9999), 2000);
The ‘setTimeout()’ method allows executable code in the form of a string to be passed as the first parameter exposing an application to arbitrary code execution. This is usually done when dynamically creating a function and concatinating the arguments togetheras a string. The function will interpret and execute the code similar to ‘eval()’. As with ‘eval()’, this approach makes the function susceptible to command injection.
Avoid dynamically building functions as strings and instead use callbacks and declared functions.
CWE:
CWE-94: Improper Control of Generation of Code ('Code Injection')
Secure Code Warrior Training
References:
Insecure Code: Function created through string concatanation to be interpretted by the setInterval() function and susceptible to injection attacks.
var composedFunctionForInterval = 'function(messageText) {' +
'console.log(messageText);' +
'injectedMaliciousCode' +
'}}'
setInterval(composedFunctionForInterval(untrustedData), 1000);
Secure Code: Declared function to be called by setInterval() and not created via string concatination inhibiting injection attacks
const intervalFunction = function(messageText) {
// Business logic
const resultOfLogic = console.log(messageText);
}
setInterval(intervalFunction(untrustedData), 2000);
Applications responsible for password management inherit a tremendous amount of risk and responsibility. User passwords must be created with sufficient length / complexity, stored securely, and protected from brute force and cracking attempts. The following password management rules are currently supported:
Weak passwords can allow attackers to easily guess user passwords using wordlist or brute force attacks. Enforcing a strict password complexity policy mitigates these attacks by significantly increasing the time to guess a user’s valid password.
The following .NET Framework and Core password complexity classes are supported by SEC0017:
Out of the box, Visual Studio’s template for ASP.NET Identity-based authentication requires only 6 characters. Increasing the minimum length from 6 to a value greater than 12 characters will significantly increase the strength of the passwords stored by the application.
Requiring all of the character types (upper, lower, numeric, and special) increases the computational power to crack passwords.
CWE:
CWE-521: Weak Password Requirements
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/microsoft.aspnet.identity.passwordvalidator(v=vs.108).aspx
https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.passwordoptions
Insecure Code: The following example shows the ApplicationUserManager class configuring the PasswordValidator with a weak password complexity policy. This configuration, which is the default policy generated by Visual Studio, sets a minimum password length of 6 characters.
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6
};
Secure Code: Update the PasswordValidator configuration to meet your organization’s password complexity requirements. The following example shows a required length of 12 characters, along with at least one digit, upper, lower, and special character.
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 12,
RequireDigit = true,
RequireLowercase = true,
RequireNonLetterOrDigit = true,
RequireUppercase = true
};
Password lockout mechanisms help prevent continuous brute force attacks again user accounts by disabling an account for a period of time after a number of invalid attempts.
The ASP.NET Identity SignInManager protects against brute force attacks if the lockout parameter is set to true.
CWE:
CWE-307: Improper Restriction of Excessive Authentication Attempts
Secure Code Warrior Training
References:
Insecure Code: The following example shows the SignInManager.PasswordSignInAsync method passing false in the lockoutOnFailure parameter. This disables the Identity password lockout mechanism.
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
var user = await _userManager.FindByNameAsync(model.Username);
[...]
var result = await _signInManager.CheckPasswordSignInAsync(user, model.Password, false);
[...]
};
Secure Code: Change the lockoutOnFailure parameter value to true.
{
var user = await _userManager.FindByNameAsync(model.Username);
[...]
var result = await _signInManager.CheckPasswordSignInAsync(user, model.Password, true);
[...]
};
Weak validation can allow attackers to take advantage of the application and attack other users. The following validation rules are currently supported:
Cross Site Request Forgery attacks occur when a victim authenticates to a target web site and then visits a malicious web page. The malicious web page then sends a fake HTTP request (GET, POST, etc.) back to the target website. The victim’s valid authentication cookie from the target web site is automatically included in the malicious request, sent to the target web site, and processed as a valid transaction under the victim’s identity.
This rule searches for all actions decorated with HTTP verbs that typically modify data (POST, PUT, DELETE, and PATCH). Actions containing the [AllowAnonymous] attribute are not reported as CSRF attacks target authenticated users. Any identified actions that are missing the ValidateAntiForgeryToken attribute raise a diagnostic warning.
In ASP.NET MVC, the ValidateAntiForgeryToken attribute protects applications using authentication cookies from CSRF attacks. Actions with this attribute search the request parameters for the __RequestVerificationToken and validate the value prior to executing the request.
CWE:
CWE-352: Cross-Site Request Forgery (CSRF)
Secure Code Warrior Training
References:
Insecure Code: The following example shows the Enter action performing a transaction without using the ValidateAntiForgeryToken attribute.
[HttpPost]
public ActionResult Enter(int id, ContestEntryModel model)
{
if (ModelState.IsValid)
{
submitContestEntry(id, model);
}
}
Secure Code: By adding the ValidateAntiForgeryToken attribute, the application will validate the __RequestVerificationToken request parameter before entering the contest.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Enter(int id, ContestEntryModel model)
{
if (ModelState.IsValid)
{
submitContestEntry(id, model);
}
}
Request validation performs blacklist input validation for XSS payloads found in form and URL request parameters. Request validation has known bypass issues and does not prevent all XSS attacks, but it does provide a strong countermeasure for most payloads targeting a HTML context.
Request validation is enabled by default during model binding to dynamic HTML request parameters, but can be disabled on individual model properties using the AllowHtml attribute. The following countermeasures can help validate data and filter XSS payloads:
Version 4.3.0 is the recommended HTML sanitizer library version
CWE:
CWE-20: Improper Input Validation
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/system.web.mvc.allowhtmlattribute(v=vs.118).aspx
Insecure Code: The following example shows the ProductFeedback model setting the AllowHtml attribute on the Feedback property.
public class ProductFeedbackModel
{
[Display(Name = "Rating")]
public int Rating { get; set; }
[Display(Name = "Feedback")]
[AllowHtml]
public string Feedback { get; set; }
}
Secure Code: The following example removes the AllowHtml attribute to enable request validation.
public class ProductFeedbackModel
{
[Display(Name = "Rating")]
public int Rating { get; set; }
[Display(Name = "Feedback")]
public string Feedback { get; set; }
}
Request validation performs blacklist input validation for XSS payloads found in form and URL request parameters. Request validation has known bypass issues and does not prevent all XSS attacks, but it does provide a strong countermeasure for most payloads targeting a HTML context.
Request validation is enabled by default during model binding to dynamic HTML request parameters, but can be disabled on controllers and actions properties using the ValidateInput(false) attribute. The following countermeasures can help validate data and filter XSS payloads:
Version 4.3.0 is the recommended HTML sanitizer library version
CWE:
CWE-20: Improper Input Validation
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/system.web.mvc.validateinputattribute.aspx
Insecure Code: The following example shows the Save action using the ValidateInput(false) attribute to disable request validation.
[HttpPost]
[ValidateInput(false)]
public ActionResult Save(int id, ProductFeedbackModel model)
{
}
Secure Code: The following example removes the ValidateInput(false) attribute to enable request validation.
[HttpPost]
public ActionResult Save(int id, ProductFeedbackModel model)
{
}
Passing unvalidated redirect locations to the MVC Controller.Redirect method can allow attackers to send users to malicious web sites. This can allow attackers to perform phishing attacks and distribute malware to victims.
Avoid performing redirect actions with user controllable data (e.g. request parameters). Consider validating redirect paths to allow relative paths inside of the application and deny absolute paths. All absolute paths must be validated against an approved list of external domains prior to redirecting the user.
CWE:
CWE-601: URL Redirection to Untrusted Site ('Open Redirect')
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/system.web.mvc.controller.redirect(v=vs.118).aspx
Insecure Code: The following example shows the Controller Redirect method called using an unvalidated request parameter.
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
[perform auth logic]
return this.Redirect(returnUrl);
}
Secure Code: Validate the return URL is a local path (not absolute) to ensure an attacker cannot redirect the user to a malicious external domain.
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
[perform auth logic]
if (Url.IsLocalUrl(returnUrl))
{
return this.Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
Passing unvalidated redirect locations to the Response.Redirect method can allow attackers to send users to malicious web sites. This can allow attackers to perform phishing attacks and distribute malware to victims.
Avoid performing redirect actions with user controllable data (e.g. request parameters). Consider validating redirect paths to allow relative paths inside of the application and deny absolute paths. All absolute paths must be validated against an approved list of external domains prior to redirecting the user.
CWE:
CWE-601: URL Redirection to Untrusted Site ('Open Redirect')
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/a8wa7sdt(v=vs.110).aspx
Insecure Code: The following example shows the Response.Redirect method called using an unvalidated request parameter.
if (Request.QueryString["ReturnUrl"] != null)
Response.Redirect(Request.QueryString["ReturnUrl"]);
Secure Code: Validate the return URL is a relative path (not absolute) to ensure an attacker cannot redirect the user to a malicious external domain.
Uri targetUri = null;
if (Uri.TryCreate(Request.QueryString["ReturnUrl"], UriKind.Relative, out targetUri))
{
Response.Redirect(targetUri.ToString());
}
else
{
Response.Redirect("~/default.aspx");
}
Path traversal vulnerabilities occur when an application does not properly validate file paths for directory traversal (../) and other malicious characters. This can allow attackers to download, overwrite, or delete unauthorized files from the server. Ensure file paths are read from a trusted location, such as a static resource or configuration file. Do not send file paths in request parameters, which can be modified by an attacker.
The ASP.NET MVC FilePathResult and FileStreamResult actions are used to stream file content to the browser.
Failing to validate the file path used by these actions can allow path traversal vulnerabilities. Ensure that all user input is properly validated and sanitized before it is passed to the file API.
CWE:
CWE-23: Relative Path Traversal
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/system.web.mvc.filepathresult(v=vs.118).aspx
https://docs.microsoft.com/en-us/previous-versions/aspnet/web-frameworks/dd492941(v=vs.118)
Insecure Code: The following example shows the FilePathResult action result using the fileName request parameter to construct the file path location.
[HttpPost]
public FileResult Download(string fileName)
{
string filePath = ConfigurationManager.AppSettings["DownloadDirectory"].ToString();
return new FilePathResult(filePath + fileName, "application/octet-stream");
}
Secure Code: Avoid using untrusted values when constructing a file path. Instead, store file paths in a trusted location, such as a configuration file, and use a unique identifier to construct the file name.
[HttpPost]
public FileResult Download(Guid fileId)
{
string filePath = ConfigurationManager.AppSettings["DownloadDirectory"].ToString();
filePath = string.Format("{0}{1}.pdf", filePath, fileId.ToString());
return new FilePathResult(filePath, "application/octet-stream");
}
Path traversal vulnerabilities occur when an application does not properly validate file paths for directory traversal (../) and other malicious characters. This can allow attackers to download, overwrite, or delete unauthorized files from the server. Ensure file paths are read from a trusted location, such as a static resource or configuration file. Do not send file paths in request parameters, which can be modified by an attacker.
SEC0112 scans the System.IO.FileStream API that is commonly called with dynamic file path data.
Dynamic file paths passed to a file stream require strict validation. Ensure file paths are read from a trusted location, such as a static resource or configuration file. Do not send file paths in request parameters, which can be modified by an attacker to contain dangerous characters (../).
CWE:
CWE-23: Relative Path Traversal
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/system.io.filestream(v=vs.110).aspx
Insecure Code: The following example shows a FileStream being constructed from a dynamic parameter to determine the file path location.
public ActionResult Index(string fileName)
{
using (Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return new FileStreamResult(stream, fileName);
}
}
Secure Code: Avoid using untrusted values when constructing a file path. Instead, store file paths in a trusted location, such as a configuration file, and use a unique identifier to construct the file name.
public ActionResult Index(Guid fileId)
{
string path = Path.Combine(ConfigurationManager.AppSettings["DownloadPath"], fileId.ToString());
//NOTE: YOU MAY STILL NEED TO PERFORM ENTITLEMENT AUTHORIZATION BEFORE RETURNING THE FILE
using (Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return new FileStreamResult(stream, fileName);
}
}
Disabling certificate validation is common in testing and development environments. Quite often, this is accidentally deployed to production, leaving the application vulnerable to man-in-the-middle attacks on insecure networks.
The following .NET 6, .NET Core and .NET Framework classes are supported by SEC0113:
Do not override the ServerCertificateValidationCallback or ServerCertificateCustomValidationCallback methods to always return true. If the development team is using self-signed certificates, use certificate pinning to ensure the application will only communicate with the trusted server certificate.
CWE:
CWE-295: Improper Certificate Validation
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning
Insecure Code: The following example shows the HttpClientHandler.ServerCertificateCustomValidationCallback method being overridden to always return a true value.
using (var handler = new HttpClientHandler())
{
handler.ServerCertificateCustomValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
using (var client = new HttpClient(handler))
{
var request = await client.GetAsync($"{BASE_URL}{endpoint}");
var json = await request.Content.ReadAsStringAsync();
item = JsonConvert.DeserializeObject<T>(json);
}
}
Secure Code: This one is too easy. Don’t override the frameworks certificate validation to always return true.
using (var handler = new HttpClientHandler())
{
using (var client = new HttpClient(handler))
{
var request = await client.GetAsync($"{BASE_URL}{endpoint}");
var json = await request.Content.ReadAsStringAsync();
item = JsonConvert.DeserializeObject<T>(json);
}
}
Path traversal vulnerabilities occur when an application does not properly validate file paths for directory traversal (../) and other malicious characters. This can allow attackers to download, overwrite, or delete unauthorized files from the server.
Ensure file paths are read from a trusted location, such as a static resource or configuration file. Do not send file paths in request parameters, which can be modified by an attacker to contain dangerous characters (../).
SEC0116 covers several APIs that are commonly called with dynamic file path data. Any of the following method calls require strict validation on the files being consumed by the API:
CWE:
CWE-23: Relative Path Traversal
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/system.io.file(v=vs.110).aspx
Insecure Code: The following example shows the File.Delete method called using a dynamic parameter from a REST service to construct the file path location.
public HttpResponseMessage Delete(string file)
{
string path = Path.Combine(ConfigurationManager.AppSettings["DownloadPath"], file);
File.Delete(path);
return Request.CreateResponse(HttpStatusCode.OK);
}
Secure Code: Avoid using untrusted values when constructing a file path. Instead, store file paths in a trusted location, such as a configuration file, and use a unique identifier to construct the file name.
[HttpPost]
public HttpResponseMessage Delete(Guid fileId)
{
string path = Path.Combine(ConfigurationManager.AppSettings["DownloadPath"], fileId.ToString());
//NOTE: YOU STILL NEED TO AUTHORIZE THE USERS ENTITLEMENTS ON DELETING THIS FILE :)
File.Delete(path);
return Request.CreateResponse(HttpStatusCode.OK);
}
Server-side Request Forgery (SSRF) vulnerabilities occur when an application requests data from a URL supplied from an untrusted location (e.g. request parameter, web service API, database). Attackers can supply a malicious URL to the application, which can allow unauthorized access to secrets, database data, and files hosted on the server. Common examples include cloud meta-data endpoints (e.g. http://169.254.169.254/), database administrator REST APIs, or local file URIs (e.g. file://).
SEC0129 identifies untrusted URLs passed to the following libraries:
To prevent Server-side Request Forgery (SSRF) vulnerabilities, follow this pattern:
Does the user really need to directly control the full URL passed to the application? The answer is usually No. Consider moving the URL value to server-side storage and look up the value using a non-injectable value such as a GUID, integer, etc. passed in from the request. For example, consider an application that allows the user to request data from two URIs:
URI | ID |
---|---|
https://pumasecurity.io/api/rules | 06C67D8C-CAD5-4003-B065-1089CFF0D1E9 |
https://pumascan.com/api/rules | A180A8AF-C667-4074-A768-C95F13819E2A |
Requests pass in a valid GUID and the application selects the associated URL. If the GUID is not valid, throw an exception. This ensures that the user can only access approved URIs.
Validate incoming URLs against a strict list of approved URIs reject everything else.
CWE:
CWE-918: Server-Side Request Forgery (SSRF)
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/Server_Side_Request_Forgery
https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient
https://docs.microsoft.com/en-us/dotnet/api/system.net.httpwebrequest
https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httprequestmessage.requesturi
Insecure Code: The following example shows a url request parameter being passed to the HttpClient GetAsync method without validating the URL against a list of trusted URIs.
public async IActionResult Get(string url)
{
var client = new HttpClient();
var request = client.GetAsync(url);
var json = await result.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<GetResult>(json);
}
Secure Code:
public async IActionResult Get(Guid urlId)
{
//Pull valid endpoints from the configuration file
List<Endpoint> endpoints = GetEndpoints();
//Verify the endpoint exists
Endpoint e = endpoints.FirstOrDefault(i => i.Id == urlId);
if (e == null)
throw new ArgumentException("Invalid endpoint id.");
var client = new HttpClient();
var request = client.GetAsync(e.Url);
var json = await result.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<GetResult>(json);
}
Access control issues can allow attackers to vertically escalate privileges or horizontally perform actions on behalf of another user in a vulnerable application. Detecting access control issues with automated static analysis tools is difficult because most issues occur in business logic. Automated tools, including code analyzers, are not capable of understanding the service’s rules or the context in which data is being handled.
The following rules detect the misconfiguration of authentication services and the absence of an expected access control protection. For the reasons mentioned above, please understand that the rules in the category may be noisy and produce more false positives than normal. Should a rule not provide value in a particular application or service, leverage the Rule Configuration to disable the rule.
Cross-Origin Resource Sharing (CORS) allows a service to disable the browser’s Same-origin policy, which prevents scripts on an attacker-controlled domain from accessing resources and data hosted on a different domain. The CORS Access-Control-Allow-Origin HTTP header specifies the domain with permission to invoke a cross-origin service and view the response data. Configuring the Access-Control-Allow-Origin header with a wildcard (*) can allow code running on an attacker-controlled domain to view responses containing sensitive data.
SEC0121 identifies .NET CORS misconfigurations using the AllowAnyOrigin() method.
Avoid setting the Access-Control-Allow-Origin header to a wildcard (*). Instead, configure the service to validate the incoming Origin header value against a trusted list of domains. Return the incoming accepted domain in the Access-Control-Allow-Origin header value, otherwise default the Access-Control-Allow-Origin value to a known safe origin.
CWE:
CWE-942: Overly Permissive Cross-domain Whitelist
Secure Code Warrior Training
References:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
https://www.youtube.com/watch?reload=9&v=wgkj4ZgxI4c
https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.2
Insecure Code: The following example shows a CORS configuration using the AllowAnyOrigin configuration, which sets the Access-Control-Allow-Origin header to the wildcard (*)
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
app.UseCors(builder => builder.AllowAnyOrigin());
...
}
Secure Code: The following example shows the ConfigureServices method creating a _secureOrigin policy with a trusted list of domains. Then, the Configure method configures the CORS policy to usee the _secureOrigin policy.
private readonly string secureOrigin = "_secureOrigin";
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(secureOrigin,
builder =>
{
builder.WithOrigins("https://www.pumasecurity.io",
"https://www.pumascan.com");
});
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
app.UseCors(secureOrigin);
...
}
The JSON Web Tokens (JWT) header and payload values are base64 encoded, which can be decoded, tampered, and replayed to gain access to protected resources.
Web service APIs relying on JSON Web Tokens (JWT) for authentication and authorization must sign each JWT with a private key or secret. Each web service endpoint must require JWT signature validation prior to decoding and using the token to access protected resources.
In ASP.NET Core, configure the Authentication service’s JwtBearer options to require signed tokens:
CWE:
CWE-347: Improper Verification of Cryptographic Signature
Secure Code Warrior Training
References:
https://cheatsheets.pragmaticwebsecurity.com/cheatsheets/jwt.pdf
https://tools.ietf.org/html/rfc7519#section-11.2
https://docs.microsoft.com/en-us/dotnet/api/microsoft.identitymodel.tokens.tokenvalidationparameters
Insecure Code: The following example shows the TokenValidationParameters.RequireSignedTokens property set to false.
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
[...]
RequireSignedTokens = false,
};
});
Secure Code: Set the TokenValidationParameters.RequireSignedTokens property to true.
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
[...]
RequireSignedTokens = true,
};
});
Insecure Secrets Management vulnerabilities occur when sensitive values (e.g. private SSH keys, API tokens, system passwords, encryption keys, etc.) are not encrypted at rest. This commonly occurs when storing secrets in source code, configuration files, or properties files. Storing secrets in cleartext can leak secrets to anyone with access to the source code or binary files.
Rather than storing secrets in source code, store secrets in a dedicated secrets management system separate from the application or service consuming the secret values. Common secrets management solutions are:
Hard-coding credentials in source code allows anyone with access to the source control repository or the binary files to obtain the credential. Rotating hard-coded secrets is also difficult because the application or service must be redeployed to change the value.
SEC0130 detects hard-coded credentials used to create the following:
Rather than storing credentials in source code, store secrets in a dedicated secrets management system (Azure Key Vault, Amazon KMS, Google KMS, HashiCorp Vault) separate from the application or service consuming the secret values.
CWE:
CWE-798: Use of Hard-coded Credentials
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/Use_of_hard-coded_password
https://docs.microsoft.com/en-us/dotnet/api/system.net.networkcredential
https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets
https://docs.microsoft.com/en-us/aspnet/core/security/key-vault-configuration
Insecure Code: The following example shows a hard-coded SMTP NetworkCredential.
using (SmtpClient client = new SmtpClient())
{
client.Credentials = new NetworkCredential("noreply@pumasecurity.io"
, "supersecretpassword");
}
Secure Code: Start by burning the credential. Read the new network credential from an external secrets management system, such as Azure Vault.
using (SmtpClient client = new SmtpClient())
{
client.Credentials = new NetworkCredential("noreply@pumasecurity.io"
, getVaultSecret("smtp/noreply/credential"));
}
Hard-coding secrets such as encryption keys, initialization vectors, and passwords in source code allows anyone with access to the source control repository or the binary files to obtain the values. Rotating hard-coded secrets is also difficult because the application or service must be redeployed to change the value.
SEC0131 searches for hard-coded variable names matching the following regular expressions. See the Rule Options to customize the search expressions.
Rather than storing secrets in source code, store secrets in a dedicated secrets management system (Azure Key Vault, Amazon KMS, Google KMS, Hashicorp Vault) separate from the application or service consuming the secret values.
CWE:
CWE-798: Use of Hard-coded Credentials
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/Use_of_hard-coded_password
https://docs.microsoft.com/en-us/dotnet/api/system.net.networkcredential
https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets
https://docs.microsoft.com/en-us/aspnet/core/security/key-vault-configuration
Insecure Code: The following example shows a hard-coded encryption key and initialization vector.
public class Symmetric
{
private readonly string KEY = "D87D016B70393029";
private readonly byte[] IV = { 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110 };
...
}
Secure Code: Start by burning the hard-coded values. Read the new symmetric encryption key from the Vault, and generate a random IV for each encryption operation.
public class Symmetric
{
private readonly byte[] KEY;
private readonly byte[] IV;
public Symmetric()
{
KEY = getVaultSecret("puma/services/key");
IV = getCryptoRandomIV();
}
...
}
During code analysis, Puma Scan builds an inventory of open source package references for .NET found in packages.config and .csproj files.
Users can opt-in to enhanced open source security analysis by enabling rule id SEC0039 in the scan configuration file (.pumafile). Doing so will share the application’s package inventory with the following third-party databases to identify vulnerable open source packages:
Dependencies on open source frameworks and packages introduce additional vulnerabilities into the runtime environment. Vulnerabilities in open source libraries are continuously discovered and documented in publicly available vulnerability databases. Attackers can recognize a package being used by an application, and leverage known vulnerabilities in the library to attack the application. Severe vulnerabilities in dependencies can lead to authentication bypass, cross-site scripting, injection, path traversal, remote code execution and other attacks against the target application.
Monitor open source package references for security advisories published in publicly available vulnerability databases. Develop a zero-day plan that includes a course of action if a vulnerable library is discovered. Upgrade package references to the latest version known to patch the vulnerability. If the vulnerability has not been fixed, configure virtual patching, such as WAF or RASP, to temporarily protect the application.
CWE:
CWE-937: Using Components with Known Vulnerabilities
Secure Code Warrior Training
References:
Insecure Code: The following example shows an older version of bootstrap (v3.0) referenced in the packages.config file. Bootstrap v3.0 contains several known cross-site scripting vulnerabilities.
<package id="bootstrap" version="3.0.0" targetFramework="net462" />
Secure Code: To patch the known vulnerabilities, upgrade the bootstrap package reference to v4.5.3.
<package id="bootstrap" version="4.5.3" targetFramework="net462" />
Security rules for “Classic” .NET Framework which refers to versions 4.8 and earlier of the standard Microsoft .NET Runtime that ships with Windows, and is not based on .NET Core.
Binaries compiled in debug mode can leak detailed stack traces and debugging messages to attackers.
Disable debug builds by setting the debug attribute to false.
CWE:
CWE-11: ASP.NET Misconfiguration: Creating Debug Binary
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/s10awwz0(v=vs.100).aspx
Insecure Configuration: The default value for the debug attribute is false.
<system.web>
...
<compilation debug="true" targetFramework="4.5"/>
...
</system.web>
Secure Configuration: Remove the debug attribute, or explicitly set the value to false.
<system.web>
...
<compilation debug="false" targetFramework="4.5"/>
...
</system.web>
Displaying stack traces in the browser can leak information to attackers and help them gain information for launching additional attacks.
Enable custom errors by setting the mode to On or RemoteOnly.
CWE:
CWE-12: ASP.NET Misconfiguration: Missing Custom Error Page
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/h0hfz6fc(v=vs.100).aspx
Insecure Configuration: The default value for the mode attribute is RemoteOnly.
<system.web>
...
<customErrors mode="Off" defaultRedirect="/home/error"/>
...
</system.web>
Secure Configuration: Explicitly set the mode value to RemoteOnly or On, or simply remove the mode attribute.
<system.web>
...
<customErrors mode="RemoteOnly|On" defaultRedirect="/home/error"/>
...
</system.web>
Enabling cross-application redirects can allow unvalidated redirect attacks via the returnUrl parameter during the login process.
Disable cross-application redirects to by setting the enableCrossAppRedirects attribute to false.
CWE:
CWE-601: URL Redirection to Untrusted Site
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/1d3t3c61(v=vs.100).aspx
Insecure Configuration: The following example shows the enableCrossAppRedirects attribute set to true.
<system.web>
...
<authentication mode="Forms">
<forms loginUrl="~/Account/Login.aspx" enableCrossAppRedirects="true" />
</authentication>
...
</system.web>
Secure Configuration: Explicitly set the enableCrossAppRedirects attribute to false, or simply remove the insecure configuration. The default value for enableCrossAppRedirects is false.
<system.web>
...
<authentication mode="Forms">
<forms loginUrl="~/Account/Login.aspx" enableCrossAppRedirects="false" />
</authentication>
...
</system.web>
Excessive authentication timeout values provide attackers with a large window of opportunity to hijack user’s authentication tokens.
Configure the forms timeout value to meet your organization’s timeout policy. If your organization does not have a timeout policy, the following guidance can be used:
App | Timeout |
---|---|
High Security | 15 minutes |
Medium Security | 30 minutes |
Low Security | 60 minutes |
The default forms authentication timeout value is 30 minutes.
CWE:
CWE-613: Insufficient Session Expiration
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/1d3t3c61(v=vs.100).aspx
Insecure Configuration: The following examples shows the forms authentication cookie timeout set to 480 minutes (8 hours).
<system.web>
...
<authentication mode="Forms">
<forms loginUrl="~/Account/Login.aspx" timeout="480" />
</authentication>
...
</system.web>
Secure Configuration: Explicitly set the timeout attribute to an appropriate value.
<system.web>
...
<authentication mode="Forms">
<forms loginUrl="~/Account/Login.aspx" timeout="15" />
</authentication>
...
</system.web>
Disabling the HTTP Runtime header checking protection opens the application up to HTTP Header Injection (aka Response Splitting) attacks.
Enable the header checking protection by setting the httpRuntime element’s enableHeaderChecking attribute to true, which is the default value.
CWE:
CWE-113: Improper Neutralization of CRLF Sequences in HTTP Headers
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/e1f13641(v=vs.100).aspx
Insecure Configuration: The default value for the enableHeaderChecking attribute is true.
<system.web>
...
<httpRuntime enableHeaderChecking="false" />
...
</system.web>
Secure Configuration: Explicitly set the enableHeaderChecking attribute to true, or simply remove the insecure configuration.
<system.web>
...
<httpRuntime enableHeaderChecking="true" />
...
</system.web>
The Version HTTP response header sends the ASP.NET framework version to the client’s browser. This information can help an attacker identify vulnerabilities in the server’s framework version and should be disabled in production.
Disable the version response header by setting the httpRuntime element’s enableVersionHeader attribute to false.
CWE:
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/e1f13641(v=vs.100).aspx
Insecure Configuration: The default value for the enableVersionHeader attribute is true.
<system.web>
...
<httpRuntime enableVersionHeader="true" />
...
</system.web>
Secure Configuration: Explicitly set the enableVersionHeader attribute to false, or simply remove the insecure configuration.
<system.web>
...
<httpRuntime enableVersionHeader="false" />
...
</system.web>
Event validation prevents unauthorized post backs in web form applications. Disabling this feature can allow attackers to forge requests from controls not visible or enabled on a given web form.
Enable event validation by setting the page element’s eventValidation attribute to true.
CWE:
CWE-807: Reliance on Untrusted Inputs in a Security Decision
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/950xf363(v=vs.100).aspx
Insecure Configuration: The default value for the enableEventValidation attribute is true.
<system.web>
...
<pages enableEventValidation="false" />
...
</system.web>
Secure Configuration: Explicitly set the enableEventValidation attribute to true, or simply remove the insecure configuration.
<system.web>
...
<pages enableEventValidation="true" />
...
</system.web>
The ViewStateMac protection prevents tampering with the web forms view state and event validation hidden fields. Disabling this feature can allow attackers to manipulate these fields in the browser and bypass several security features in the .NET framework.
Enable the view state mac protection by setting the page element’s viewStateMac attribute to true.
As of .NET version 4.5.1, the ViewStateMac can no longer be disabled.
CWE:
CWE-807: Reliance on Untrusted Inputs in a Security Decision
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/950xf363(v=vs.100).aspx
Insecure Configuration: The default value for the enableViewStateMac attribute is true.
<system.web>
...
<pages enableViewStateMac="false" />
...
</system.web>
Secure Configuration: Explicitly set the enableViewStateMac attribute to true, or simply remove the insecure configuration.
<system.web>
...
<pages enableViewStateMac="true" />
...
</system.web>
The ValidateRequest protection denies known malicious XSS payloads found in form and URL request parameters. Request validation has known bypass issues and does not prevent all XSS attacks, but it does provide a strong countermeasure for most payloads targeting a HTML context.
Request validation should be enabled by setting the page element’s requestValidation attribute to true. Then, consider making exceptions or overriding the default behavior on individual request parameters.
CWE:
CWE-20: Improper Input Validation
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/950xf363(v=vs.100).aspx
Insecure Configuration: The default value for the validateRequest attribute is true.
<system.web>
...
<pages validateRequest="false" />
...
</system.web>
Secure Configuration: Explicitly set the validateRequest attribute to true, or simply remove the insecure configuration.
<system.web>
...
<pages validateRequest="true" />
...
</system.web>
The web forms view state hidden field is base64 encoded by default, which can be easily decoded. Applications placing sensitive data into the view state are vulnerable to information leakage issues via the view state parameter.
Configure the pages element’s viewStateEncryptionMode attribute to Always to encrypt the view state data with the .NET machine key.
CWE:
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/950xf363(v=vs.100).aspx
Insecure Configuration: The default value for the viewStateEncryptionMode attribute is Auto, which only encrypts view state data for controls that request encryption.
<system.web>
...
<pages viewStateEncryptionMode="Never" />
...
</system.web>
Secure Configuration: Explicitly set the viewStateEncryptionMode attribute to Always.
<system.web>
...
<pages viewStateEncryptionMode="Always" />
...
</system.web>
The machine key element defines keys to use for encryption, decryption, and HMAC validation of authentication cookies, view state, event validation, and other framework fields. The validation and decryption key values should not be stored in configuration files in cleartext.
Cleartext machine key validation and decryption values became a high risk to .NET Web Forms applications when @jared_mclaren presented a talk titled RCEvil.NET - A Super Serial Story at @BSidesIowa 2019. This talk released a tool that enables remote attackers knowing the machine keys to anonymously gain Remote Code Execution (RCE) on IIS web servers.
Encrypt the machineKey section of the configuration file using aspnet_regiis.exe.
CWE:
CWE-312: Cleartext Storage of Sensitive Information
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/w8h3skw9(v=vs.100).aspx
Insecure Configuration: Secrets stored in the web.config file are not encrypted by default.
<system.web>
...
<machineKey validationKey="NOTASECRETANYMORE" decryptionKey="NOTASECRETANYMORE" validation="SHA1" decryption="AES"/>
...
</system.web>
Secure Configuration: Use the aspnet_regiis.exe utility to encrypt the machineKey element of the configuration file. Run this command from the root of your app.
C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe -pef "system.web/machineKey" . -prov "DataProtectionConfigurationProvider"
<system.web>
...
<machineKey configProtectionProvider="DataProtectionConfigurationProvider">
<EncryptedData>
<CipherData>
<CipherValue>85c0b357d397d3e63f03e5b6ae299d66</CipherValue>
</CipherData>
</EncryptedData>
</machineKey>
...
</system.web>
If session data is used by the application for authentication, excessive timeout values provide attackers with a large window of opportunity to hijack user’s session tokens.
Configure the session timeout value to meet your organization’s timeout policy. If your organization does not have a timeout policy, the following guidance can be used:
App | Timeout |
---|---|
High Security | 15 minutes |
Medium Security | 30 minutes |
Low Security | 60 minutes |
The default session timeout value is 20 minutes.
CWE:
CWE-613: Insufficient Session Expiration
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/h6bb9cz9(v=vs.100).aspx
Insecure Configuration: The example below shows an excessive timeout value of 480 minutes (8 hours).
<system.web>
...
<sessionState timeout="480" />
...
</system.web>
Secure Configuration: Explicitly set the timeout attribute to an appropriate value.
<system.web>
...
<sessionState timeout="15" />
...
</system.web>
The session StateServer mode transports session data insecurely to a remote server. The remote server also does not require system authentication to access the session data for an application. This risk depends entirely on the sensitivity of the data stored in the user’s session.
If the session data is considered sensitive, consider adding an external control (e.g. IPSEC) that provides mutual authentication and transport security.
CWE:
CWE-319: Cleartext Transmission of Sensitive Information
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/h6bb9cz9(v=vs.100).aspx
Insecure Configuration: The default value for the mode attribute is InProc, which uses in memory session storage on the web server. Options such as StateServer allow another server to handle session management in a multi-node web farm scenario.
<system.web>
...
<sessionState mode="StateServer" />
...
</system.web>
Secure Configuration: Use a different distributed session state provider, such as SQLServer, that supports system authentication and encrypted data transmission. Or, implement an external control for system to system authentication and secure transmission, such as IPSec.
<system.web>
...
<sessionState mode="SQLServer" />
...
</system.web>
Directory listing provides a complete index of the resources located in a web directory. Enabling directory listing can expose sensitive resources such as application binaries, configuration files, and static content that should not be exposed.
Unless directory listing is required to meet the application’s functional requirements, disable the listing by setting the directoryBrowse element’s enabled attribute to false.
CWE:
CWE-548: Information Exposure Through Directory Listing
Secure Code Warrior Training
References:
https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration
https://docs.microsoft.com/en-us/iis/configuration/system.webserver/directorybrowse
Insecure Code: The following example shows the directoryBrowse enabled attribute set to true, which enables directory listing information in the browser.
<system.webServer>
<directoryBrowse enabled="true"/>
</system.webServer>
Secure Code: Set the directoryBrowse enabled attribute to false. Or, remove the directoryBrowse element to inherit the default value of false.
<system.webServer>
<directoryBrowse enabled="false"/>
</system.webServer>
Data is written to the browser using a raw write: <%= var %>. This can result in Cross-Site Scripting (XSS) vulnerabilities if the data source is considered untrusted or dynamic (request parameters, database, web service, etc.).
Instead of using a raw write, use the inline HTML encoded shortcut (<%: var %>) to automatically HTML encode data before writing it to the browser.
CWE:
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Secure Code Warrior Training
References:
https://software-security.sans.org/developer-how-to/developer-guide-xss
Insecure Code: The following example shows a raw inline expression writing a dynamic request parameter to the browser.
<h2>
Welcome <%= Request["UserName"].ToString() %>
</h2>
Secure Code: Replace the raw inline expression with the secure HTML encode inline shortcut.
<h2>
Welcome <%: Request["UserName"].ToString() %>
</h2>
Data is written to the browser using a raw binding expression: <%# Item.Variable %>. This can result in Cross-Site Scripting (XSS) vulnerabilities if the data source is considered untrusted or dynamic (request parameters, database, web service, etc.).
Instead of using a raw binding expression, use the HTML encoded binding shortcut (<%#: Item.Variable %>) to automatically HTML encode data before writing it to the browser.
CWE:
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Secure Code Warrior Training
References:
https://software-security.sans.org/developer-how-to/developer-guide-xss
Insecure Code: The following example shows a raw binding expression writing a dynamic database value to the browser.
<asp:GridView ID="gv" runat="server" ItemType="Data.Product">
<Columns>
<asp:TemplateField HeaderText="Product">
<ItemTemplate>
<%# Item.ProductName %>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Secure Code: Replace the raw binding expression with the secure HTML encode binding shortcut (<%#:).
<asp:GridView ID="gv" runat="server" ItemType="Data.Product">
<Columns>
<asp:TemplateField HeaderText="Product">
<ItemTemplate>
<%#: Item.ProductName %>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Data is written to the browser using a WebForms property that does not perform output encoding. This can result in Cross-Site Scripting (XSS) vulnerabilities if the data source is considered untrusted or dynamic (request parameters, database, web service, etc.).
WebForms controls are often found in HTML contexts, but can also appear in other contexts such as JavaScript, HTML Attribute, or URL. Fixing the vulnerability requires the appropriate Web Protection Library (aka AntiXSS) context-specific method to encode the data before setting the WebForms property.
CWE:
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/system.web.security.antixss.antixssencoder(v=vs.110).aspx
Insecure Code: The following example shows the Literal.Text property set to a dynamic database value.
litDetails.Text = product.ProductDescription;
Secure Code: Encode data passed to the Literal.Text property with the Web Protection Library’s (aka AntiXSS) appropriate context-specific method.
litDetails.Text = Encoder.HtmlEncode(product.ProductDescription);
Data is written to the browser using the raw Label.Text method. This can result in Cross-Site Scripting (XSS) vulnerabilities if the data source is considered untrusted or dynamic (request parameters, database, web service, etc.).
Label controls are often found in HTML contexts, but can also appear in other contexts such as JavaScript, HTML Attribute, or URL. Fixing the vulnerability requires the appropriate Web Protection Library (aka AntiXSS) context-specific method to encode the data before setting the Label.Text property.
CWE:
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Secure Code Warrior Training
References:
https://msdn.microsoft.com/en-us/library/system.windows.controls.label(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/system.web.security.antixss.antixssencoder(v=vs.110).aspx
Insecure Code: The following example shows the Label.Text property set to a dynamic database value.
lblDetails.Text = product.ProductDescription;
Secure Code: Encode data passed to the Label.Text property with the Web Protection Library’s (aka AntiXSS) appropriate context-specific method.
lblDetails.Text = Encoder.HtmlEncode(product.ProductDescription);