ASP。NET请求验证原因:有列表吗?

时间:2022-12-04 20:00:29

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.]

有没有人知道是什么触发了ASP ?净的HttpRequestValidationException吗?这是常见错误背后的原因:“一个潜在危险的请求。”检测到表单值,“等。”

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).

我在网上查过了,MSDN库,但是找不到文档。我知道一些生成错误的方法,但是我希望有一个完整的列表,这样我就可以防止和有选择地绕过它(我知道如何禁用页面的请求验证,但是在这种情况下这不是一个选项)。

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."]

[注意:在IE8中脚本不会加载我(正如在Meta论坛中经常描述的那样),所以我不能“添加评论”。

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.

编辑1:嗨,Oded,你是否知道一个列表记录了用来确定“潜在恶意输入字符串”的条件?这就是我要找的。

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

编辑2:@Chris Pebble:对,你说的没错。:)

5 个解决方案

#1


28  

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:

我找不到列出结论性列表的文档,但通过Reflector并对HttpRequestValidationException的使用进行一些分析,似乎以下的验证错误会导致请求验证失败:

  • A filename in one of the files POSTed to an upload.
  • 上传文件中的文件名。
  • The incoming request raw URL.
  • 传入请求原始URL。
  • The value portion of the name/value pair from any of the incoming cookies.
  • 来自任何传入cookie的名称/值对的值部分。
  • The value portion of the name/value pair from any of the fields coming in through GET/POST.
  • 来自通过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:

那么,问题是“是什么使这些东西成为危险的输入?”这似乎发生在内部方法System.Web.CrossSiteScriptingValidation中。IsDangerousString(string, out int)看起来是这样决定的:

  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. 查找值中的< or &。如果它不在那里,或者如果它是值中的最后一个字符,那么这个值是OK的。
  3. If the & character is in a &# sequence (e.g., &#160; for a non-breaking space), it's a "dangerous string."
  4. 如果&字符在&#序列中(例如, 对于一个不间断的空间),它是一个“危险的弦”。
  5. If the < character is part of <x (where "x" is any alphabetic character a-z), <!, </, or <?, it's a "dangerous string."
  6. 如果 <字符是 的一部分(其中“x”是任何字母字符a-z),则
  7. Failing all of that, the value is OK.
  8. 如果所有这些都失败,这个值是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.

包含。CrossSiteScriptingValidation类型似乎有其他的方法来确定哪些是危险的url或有效的JavaScript id,但是这些方法不会出现,至少是通过反射器分析,从而导致抛出httprequestvalidationexception。

#2


14  

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

http://referencesource.microsoft.com/包含/ 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.

在检查了最新的代码之后,您可能会同意Travis Illig所解释的是目前在2018年使用的唯一验证(自从2014年在GitHub发布源代码以来,似乎没有任何变化)。但是如果您使用旧版本的框架,下面的旧代码可能仍然是相关的。


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:

我用Reflector浏览网站。这是原始代码。当我有时间的时候,我会把它翻译成一些有意义的规则:

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

HttpRequestValidationException只由系统中的一个方法抛出。Web命名空间,因此它是相当孤立的。这里是方法:

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:

上面的方法调用CrossSiteScriptingValidation类中的IsDangerousString方法,该方法根据一系列规则对字符串进行验证。它看起来是这样的:

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.

这就是结果。这不是很容易理解,但都在这里。

#3


2  

How about this script? Your code can not detect this script, right?

这个脚本呢?你的代码不能检测到这个脚本,对吗?

";}alert(1);function%20a(){//

#4


0  

Try this regular expresson pattern.

试试这个常规的快递模式。

You may need to ecape the \ for javascript ex \\

您可能需要ecape \ ex \\ \程序

var regExpPattern = '[eE][xX][pP][rR][eE][sS][sS][iI][oO][nN]\\(|\\b[oO][nN][a-zA-Z]*\\b\\s*=|&#|<[!/a-zA-Z]|[sS][cC][rR][iI][pP][tT]\\s*:';
var re = new RegExp("","gi");
re.compile(regExpPattern,"gi");
var outString = null;
outString = re.exec(text);

#5


-1  

From MSDN:

从MSDN:

'The exception that is thrown when a potentially malicious input string is received from the client as part of the request data. '

当从客户端接收到作为请求数据一部分的潜在恶意输入字符串时抛出的异常。”

Many times this happens when JavaScript changes the values of a server side control in a way that causes the ViewState to not agree with the posted data.

很多时候,当JavaScript改变服务器端控件的值时,会导致ViewState与已发布的数据不一致。

#1


28  

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:

我找不到列出结论性列表的文档,但通过Reflector并对HttpRequestValidationException的使用进行一些分析,似乎以下的验证错误会导致请求验证失败:

  • A filename in one of the files POSTed to an upload.
  • 上传文件中的文件名。
  • The incoming request raw URL.
  • 传入请求原始URL。
  • The value portion of the name/value pair from any of the incoming cookies.
  • 来自任何传入cookie的名称/值对的值部分。
  • The value portion of the name/value pair from any of the fields coming in through GET/POST.
  • 来自通过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:

那么,问题是“是什么使这些东西成为危险的输入?”这似乎发生在内部方法System.Web.CrossSiteScriptingValidation中。IsDangerousString(string, out int)看起来是这样决定的:

  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. 查找值中的< or &。如果它不在那里,或者如果它是值中的最后一个字符,那么这个值是OK的。
  3. If the & character is in a &# sequence (e.g., &#160; for a non-breaking space), it's a "dangerous string."
  4. 如果&字符在&#序列中(例如, 对于一个不间断的空间),它是一个“危险的弦”。
  5. If the < character is part of <x (where "x" is any alphabetic character a-z), <!, </, or <?, it's a "dangerous string."
  6. 如果 <字符是 的一部分(其中“x”是任何字母字符a-z),则
  7. Failing all of that, the value is OK.
  8. 如果所有这些都失败,这个值是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.

包含。CrossSiteScriptingValidation类型似乎有其他的方法来确定哪些是危险的url或有效的JavaScript id,但是这些方法不会出现,至少是通过反射器分析,从而导致抛出httprequestvalidationexception。

#2


14  

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

http://referencesource.microsoft.com/包含/ 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.

在检查了最新的代码之后,您可能会同意Travis Illig所解释的是目前在2018年使用的唯一验证(自从2014年在GitHub发布源代码以来,似乎没有任何变化)。但是如果您使用旧版本的框架,下面的旧代码可能仍然是相关的。


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:

我用Reflector浏览网站。这是原始代码。当我有时间的时候,我会把它翻译成一些有意义的规则:

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

HttpRequestValidationException只由系统中的一个方法抛出。Web命名空间,因此它是相当孤立的。这里是方法:

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:

上面的方法调用CrossSiteScriptingValidation类中的IsDangerousString方法,该方法根据一系列规则对字符串进行验证。它看起来是这样的:

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.

这就是结果。这不是很容易理解,但都在这里。

#3


2  

How about this script? Your code can not detect this script, right?

这个脚本呢?你的代码不能检测到这个脚本,对吗?

";}alert(1);function%20a(){//

#4


0  

Try this regular expresson pattern.

试试这个常规的快递模式。

You may need to ecape the \ for javascript ex \\

您可能需要ecape \ ex \\ \程序

var regExpPattern = '[eE][xX][pP][rR][eE][sS][sS][iI][oO][nN]\\(|\\b[oO][nN][a-zA-Z]*\\b\\s*=|&#|<[!/a-zA-Z]|[sS][cC][rR][iI][pP][tT]\\s*:';
var re = new RegExp("","gi");
re.compile(regExpPattern,"gi");
var outString = null;
outString = re.exec(text);

#5


-1  

From MSDN:

从MSDN:

'The exception that is thrown when a potentially malicious input string is received from the client as part of the request data. '

当从客户端接收到作为请求数据一部分的潜在恶意输入字符串时抛出的异常。”

Many times this happens when JavaScript changes the values of a server side control in a way that causes the ViewState to not agree with the posted data.

很多时候,当JavaScript改变服务器端控件的值时,会导致ViewState与已发布的数据不一致。