Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET request validation causes: is there a list?

Tags:

c#

.net

asp.net

is anybody aware of a list of exactly what triggers ASP.NET's HttpRequestValidationException? [This is behind the common error: "A potentially dangerous Request.Form value was detected," etc.]

I've checked here, around the Web, and MSDN Library but can't find this documented. I'm aware of some ways to generate the error, but would like to have a complete list so I can guard against and selectively circumvent it (I know how to disable request validation for a page, but this isn't an option in this case).

Is it a case of "security through obscurity"?

Thanks.

[Note: Scripts won't load for me in IE8 (as described frequently in the Meta forum) so I won't be able to "Add comment."]

EDIT 1: Hi Oded, are you aware of a list that documents the conditions used to determine a "potentially malicious input string"? That's what I'm looking for.

EDIT 2: @Chris Pebble: Yeah, what you said. :)

like image 501
TK-421 Avatar asked Feb 04 '10 15:02

TK-421


People also ask

What is RequestValidationMode?

The RequestValidationMode property specifies which ASP.NET approach to validation will be used. This can be the algorithm that is used in versions of ASP.NET earlier than version 4, or the version that is used in . NET Framework 4. The property can be set to the following values: 4.5 (the default).

Which attribute can be used to disable request validation for a property?

You can disable request validation by setting validateRequest=false in the Page directive or in the configuration section.

How can you bypass the validation of ASP.NET controls?

To disable validation in a specific controlSet the control's CausesValidation property to false.

What is C# validation?

The validation attributes specify behavior that you want to enforce on the model properties they are applied to. The Required attribute indicates that a property must have a value; in this sample, a movie has to have values for the Title , ReleaseDate , Genre , and Price properties in order to be valid.


2 Answers

I couldn't find a document outlining a conclusive list, but looking through Reflector and doing some analysis on use of HttpRequestValidationException, it looks like validation errors on the following can cause the request validation to fail:

  • A filename in one of the files POSTed to an upload.
  • The incoming request raw URL.
  • The value portion of the name/value pair from any of the incoming cookies.
  • The value portion of the name/value pair from any of the fields coming in through GET/POST.

The question, then, is "what qualifies one of these things as a dangerous input?" That seems to happen during an internal method System.Web.CrossSiteScriptingValidation.IsDangerousString(string, out int) which looks like it decides this way:

  1. Look for < or & in the value. If it's not there, or if it's the last character in the value, then the value is OK.
  2. If the & character is in a &# sequence (e.g., &#160; for a non-breaking space), it's a "dangerous string."
  3. If the < character is part of <x (where "x" is any alphabetic character a-z), <!, </, or <?, it's a "dangerous string."
  4. Failing all of that, the value is OK.

The System.Web.CrossSiteScriptingValidation type seems to have other methods in it for determining if things are dangerous URLs or valid JavaScript IDs, but those don't appear, at least through Reflector analysis, to result in throwing HttpRequestValidationExceptions.

like image 158
Travis Illig Avatar answered Sep 18 '22 15:09

Travis Illig


Update:

Warning: Some parts of the code in the original answer (below) were removed and marked as OBSOLETE.

Latest source code in Microsoft site (has syntax highlighting):

http://referencesource.microsoft.com/#System.Web/CrossSiteScriptingValidation.cs

After checking the newest code you will probably agree that what Travis Illig explained are the only validations used now in 2018 (and seems to have no changes since 2014 when the source was released in GitHub). But the old code below may still be relevant if you use an older version of the framework.


Original Answer:

Using Reflector, I did some browsing. Here's the raw code. When I have time I will translate this into some meaningful rules:

The HttpRequestValidationException is thrown by only a single method in the System.Web namespace, so it's rather isolated. Here is the method:

private void ValidateString(string s, string valueName, string collectionName) {     int matchIndex = 0;     if (CrossSiteScriptingValidation.IsDangerousString(s, out matchIndex))     {         string str = valueName + "=\"";         int startIndex = matchIndex - 10;         if (startIndex <= 0)         {             startIndex = 0;         }         else         {             str = str + "...";         }         int length = matchIndex + 20;         if (length >= s.Length)         {             length = s.Length;             str = str + s.Substring(startIndex, length - startIndex) + "\"";         }         else         {             str = str + s.Substring(startIndex, length - startIndex) + "...\"";         }         throw new HttpRequestValidationException(HttpRuntime.FormatResourceString("Dangerous_input_detected", collectionName, str));     } } 

That method above makes a call to the IsDangerousString method in the CrossSiteScriptingValidation class, which validates the string against a series of rules. It looks like the following:

internal static bool IsDangerousString(string s, out int matchIndex) {     matchIndex = 0;     int startIndex = 0;     while (true)     {         int index = s.IndexOfAny(startingChars, startIndex);         if (index < 0)         {             return false;         }         if (index == (s.Length - 1))         {             return false;         }         matchIndex = index;         switch (s[index])         {             case 'E':             case 'e':                 if (IsDangerousExpressionString(s, index))                 {                     return true;                 }                 break;              case 'O':             case 'o':                 if (!IsDangerousOnString(s, index))                 {                     break;                 }                 return true;              case '&':                 if (s[index + 1] != '#')                 {                     break;                 }                 return true;              case '<':                 if (!IsAtoZ(s[index + 1]) && (s[index + 1] != '!'))                 {                     break;                 }                 return true;              case 'S':             case 's':                 if (!IsDangerousScriptString(s, index))                 {                     break;                 }                 return true;         }         startIndex = index + 1;     } } 

That IsDangerousString method appears to be referencing a series of validation rules, which are outlined below:

private static bool IsDangerousExpressionString(string s, int index) {     if ((index + 10) >= s.Length)     {         return false;     }     if ((s[index + 1] != 'x') && (s[index + 1] != 'X'))     {         return false;     }     return (string.Compare(s, index + 2, "pression(", 0, 9, true, CultureInfo.InvariantCulture) == 0); } 

-

private static bool IsDangerousOnString(string s, int index) {     if ((s[index + 1] != 'n') && (s[index + 1] != 'N'))     {         return false;     }     if ((index > 0) && IsAtoZ(s[index - 1]))     {         return false;     }     int length = s.Length;     index += 2;     while ((index < length) && IsAtoZ(s[index]))     {         index++;     }     while ((index < length) && char.IsWhiteSpace(s[index]))     {         index++;     }     return ((index < length) && (s[index] == '=')); } 

-

private static bool IsAtoZ(char c) {     return (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))); } 

-

private static bool IsDangerousScriptString(string s, int index) {     int length = s.Length;     if ((index + 6) >= length)     {         return false;     }     if ((((s[index + 1] != 'c') && (s[index + 1] != 'C')) || ((s[index + 2] != 'r') && (s[index + 2] != 'R'))) || ((((s[index + 3] != 'i') && (s[index + 3] != 'I')) || ((s[index + 4] != 'p') && (s[index + 4] != 'P'))) || ((s[index + 5] != 't') && (s[index + 5] != 'T'))))     {         return false;     }     index += 6;     while ((index < length) && char.IsWhiteSpace(s[index]))     {         index++;     }     return ((index < length) && (s[index] == ':')); } 

So there you have it. It's not pretty to decipher, but it's all there.

like image 43
The Matt Avatar answered Sep 21 '22 15:09

The Matt