【问题标题】:ASP.NET request validation causes: is there a list?ASP.NET 请求验证原因:是否有列表?
【发布时间】:2010-02-04 15:21:30
【问题描述】:

是否有人知道触发 ASP.NET 的 HttpRequestValidationException 的确切列表? [这是常见错误的原因:“检测到潜在危险的 Request.Form 值”等]

我已经检查过这里、网络和 MSDN 库,但找不到此文档。我知道一些产生错误的方法,但希望有一个完整的列表,以便我可以防范并有选择地规避它(我知道如何禁用页面的请求验证,但这不是这个选项案例)。

这是“通过默默无闻的安全”的案例吗?

谢谢。

[注意:我无法在 IE8 中加载脚本(如 Meta 论坛中经常描述的那样),因此我将无法“添加评论”。]

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

编辑 2:@Chris Pebble:是的,你说的。 :)

【问题讨论】:

  • +1 似乎缺乏有关此错误的信息。查找 RequestValidation 保护的所有内容的列表将非常有用。
  • 是的,很遗憾我们不能只阅读源代码。希望读过这篇文章的人知道或可以找出答案。 [终于让他们为我安装了 Firefox,这样我就可以发表评论了——而不是我机器上的管理员。]

标签: c# .net asp.net


【解决方案1】:

我找不到概述结论性列表的文档,但是通过 Reflector 并对 HttpRequestValidationException 的使用进行了一些分析,看起来以下验证错误可能导致请求验证失败:

  • POST 到上传的文件之一中的文件名。
  • 传入的请求原始 URL。
  • 来自任何传入 cookie 的名称/值对的值部分。
  • 来自通过 GET/POST 传入的任何字段的名称/值对的值部分。

那么,问题是“什么将这些事物中的某一种定义为危险输入?”这似乎发生在一个内部方法 System.Web.CrossSiteScriptingValidation.IsDangerousString(string, out int) 看起来它是这样决定的:

  1. 在值中查找<&。如果它不存在,或者它是值中的最后一个字符,则该值是正常的。
  2. 如果& 字符位于&# 序列中(例如,  表示不间断空格),则它是一个“危险字符串”。
  3. 如果< 字符是<x(其中“x”是任意字母字符a-z)、<!</<? 的一部分,则它是一个“危险字符串”。
  4. 所有这些都失败了,该值是正常的。

System.Web.CrossSiteScriptingValidation 类型中似乎有其他方法来确定事物是危险的 URL 还是有效的 JavaScript ID,但至少通过反射器分析,这些方法不会导致抛出 HttpRequestValidationExceptions。

【讨论】:

  • 谢谢 Travis——我正在查看您的列表以及下面列出的 Matt 代码。 [我不能将它们都标记为答案吗? ;)] 所以看起来它基本上是 '
【解决方案2】:

更新:

警告:原始答案(如下)中的某些部分代码已被删除并标记为 OBSOLETE。

微软网站最新源代码(有语法高亮):

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

检查最新代码后,您可能会同意 Travis Illig explained 是 2018 年现在使用的唯一验证(并且自 2014 年发布源代码 in GitHub 以来似乎没有任何变化)。但如果您使用旧版本的框架,下面的旧代码可能仍然适用。


原答案:

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

HttpRequestValidationException 仅由 System.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));
    }
}

上述方法调用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;
    }
}

IsDangerousString 方法似乎引用了一系列验证规则,概述如下:

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] == ':'));
}

所以你有它。不太好破译,但它就在那里。

【讨论】:

  • 感谢马特先生--很好地呼吁使用反射器。我正在与 Travis 一起查看您的回复以处理此问题 - 基本上,这似乎是我们需要关注的两种情况(带 alpha 字符的左尖括号和带数字符号的 & 符号)。
【解决方案3】:

这个脚本怎么样?你的代码检测不到这个脚本吧?

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

【讨论】:

  • True。我遇到过这样的情况,脚本是这样注入的,它通过 RAZOR 令牌呈现在注释的 javascript 行中。注释的 js 包含一个 RAZOR 令牌
【解决方案4】:

试试这个正则表达式模式。

您可能需要为 javascript 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】:

    根据 Travis 的回答,“危险”字符序列列表可以简化如下;

    基于此,在 ASP.Net MVC Web 应用程序中,可以在模型字段上使用以下正则表达式验证属性,以在提交表单时引发 HttpRequestValidationException 之前触发客户端验证;

    [RegularExpression(@"^(?![\s\S]*(&#|<[a-zA-Z!\/?]))[\s\S]*$", ErrorMessage = "This field does not support HTML or allow any of the following character sequences; &quot;&amp;#&quot;, &quot;&lt;A&quot; through to &quot;&lt;Z&quot; (upper and lower case), &quot;&lt;!&quot;, &quot;&lt;/&quot; or &quot;&lt;?&quot;.")]
    

    请注意,validation 属性错误消息在服务器端验证输出时是 HTML 编码的,但在客户端验证中使用时不是,所以这个已经编码,因为我们只打算在客户端验证中看到它。

    【讨论】:

      【解决方案6】:

      来自MSDN

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

      当 JavaScript 以一种导致 ViewState 与发布的数据不一致的方式更改服务器端控件的值时,经常会发生这种情况。

      【讨论】:

      • 是的,但我认为 OP 正在寻找会触发此操作的列表字符或字符组合。他可能知道 标签会触发这个错误,但还有很多其他微妙的方法可以触发它,这就是为什么我相信他正在寻找所有触发器的完整列表。
      猜你喜欢
      • 2011-07-13
      • 2011-11-26
      • 1970-01-01
      • 2018-04-19
      • 2010-12-11
      • 2020-01-27
      • 2020-11-02
      • 2023-03-27
      • 1970-01-01
      相关资源
      最近更新 更多