如何处理“从客户端检测到潜在危险的 Request.Form 值”?

Posted

技术标签:

【中文标题】如何处理“从客户端检测到潜在危险的 Request.Form 值”?【英文标题】:How to handle "A potentially dangerous Request.Form value was detected from the client"? 【发布时间】:2022-01-01 19:22:06 【问题描述】:

我在 ASP.NET MVC Framework 应用程序的 protected void Application_Error() 处理程序中收到了一些“一般”错误。异常消息是:

从客户端检测到有潜在危险的 Request.Form 值

有很多方法可以触发它;只有一个例子是调用例如,

http:/www.mywebsite.com/http:/www.mywebsite.com/

我只想为这种异常创建一个“过滤器”,并相应地重定向或管理请求。我不想禁用它,只是为了管理它。我也不希望它属于通用的protected void Application_Error() 处理程序——或者,至少,我想在该方法内部管理它,这样它就不会被例如处理。我的日志记录。

我该如何管理?

【问题讨论】:

对此的正确响应是实际修复它并将端点标记为安全,以免出现错误。该错误是由 Microsoft 添加的,因为默认情况下,许多网站都被编写为具有类似注入的攻击。他们采取了比抱歉更安全的方法,默认情况下不允许使用看起来像 html 标记的表单数据的请求。对此的正确回应是检查您的代码,确保您在任何时候都没有将其直接呈现为 HTML 以触发此类攻击,然后告诉 ASP.NET MVC 您的端点是安全的。 错误消息,尽管它是针对传入的请求而编写的,但基本上表明您的应用程序不能保证以安全的方式编写。你不应该保留这个错误并以任何方式处理它,相反你应该确保你的应用程序可以处理表单数据,即使是看起来像 HTML 标记的东西,然后告诉 ASP.NET MVC 它是安全的。 @LasseV.Karlsen 我想避免它落入一般受保护的 void Application_Error() 中,我还有一些其他日志/东西。我需要以某种方式过滤它。你了解我的需要吗? 是的,您应该修复您的控制器和端点,使它们不会受到此类数据的攻击,然后将它们标记为安全,然后整个错误情况就会消失。你明白我在说什么吗? @LasseV.Karlsen 我怎样才能教 MVC http:/www.mywebsite.com/http:/www.mywebsite.com/ 是正确的 url? :O 【参考方案1】:

听起来您已经配置了Application_Error() 事件处理程序,但不希望您的标准日志记录包含此类错误,大概是因为它使您的日志杂乱无章,其中包含您不打算进一步调查的异常。

背景

此错误是supposed to be,由HttpRequestValidationException 表示。如果这里是这种情况,当然,这将是一个微不足道的问题。然而,根据您提供的测试用例,您实际上得到了更通用的HttpException

作为 you noted in the comments,这是由于 .NET Framework 在评估 RequestValidator 之前对 URL early in the request pipeline 中的字符进行了验证。这可能是导致HttpRequestValidationException 没有被抛出的一个因素,否则如果RequestValidatorIsValidRequestString() 方法返回false 就会发生这种情况。

解决方法

不幸的是,由于HttpException 类用于各种错误,这使得它难以处理。幸运的是,as you also discovered,您可以通过禁用web.config 中的requestPathInvalidCharacters 并配置自定义RequestValidator 来将此验证推送到RequestValidator

<configuration>
  <system.web>
    <compilation targetFramework="4.6.1" />
    <httpRuntime 
      targetFramework="4.6.1" 
      requestValidationType="CustomRequestValidator" 
      requestPathInvalidCharacters="" 
    />
  </system.web>
</configuration>

注意:requestValidationType 需要以其命名空间为前缀,假设它不在项目的根命名空间中。

requestPathInvalidCharacters 的默认值为&lt;,&gt;,*,%,&amp;,:,\,?,因此您现在需要在您的CustomRequestValidator 中重现该验证:

public class CustomRequestValidator : RequestValidator

    private static readonly char[] requestPathInvalidCharacters = new []  '<', '>', '*', '%', '&', ':', '\\' ;
    protected override bool IsValidRequestString(
        HttpContext context, 
        string value, 
        RequestValidationSource requestValidationSource, 
        string collectionKey, 
        out int validationFailureIndex
    ) 
        if (requestValidationSource is RequestValidationSource.PathInfo || requestValidationSource is RequestValidationSource.Path) 
            var errorIndex = value.IndexOfAny(requestPathInvalidCharacters);
            if (errorIndex >= 0) 
                validationFailureIndex = errorIndex;
                return false;
            
        
        return base.IsValidRequestString(
            context, 
            value, 
            requestValidationSource, 
            collectionKey, 
            out validationFailureIndex
        );
    

这首先重新创建路径验证(由value 参数表示),然后从基础RequestValidator 执行标准的开箱即用IsValidRequestString() 处理。现在这将抛出预期的HttpRequestValidationException

管理异常

在这一点上,如上所述,这现在变成了一个微不足道的问题。由于 RequestValidator 在解析 MVC 路由之前进行评估,因此您仍然不能在此处使用全局异常过滤器。但是,由于您已经设置了 Application_Error() 事件处理程序,因此您可以在您的 global.asax.cs 中通过以下方式管理它:

void Application_Error(object sender, EventArgs e)


    Exception ex = Server.GetLastError();

    if (ex is HttpRequestValidationException)
    
        Response.Clear();
        Response.StatusCode = 200;
        // Manage request as you deem appropriate; e.g.,
        Response.Redirect("~/Errors/RequestValidation/");
        Response.End();
        return;
    

    // Your current logging logic


其他细节

对于几乎每个 ASP.NET 请求,RequestValidator 被调用至少两次——一次用于 pathinfo(通常为空),一次用于path(see requestValidationSource )。每个QueryStringFormCookieHeader 或绑定到路由的文件也将被验证。

Microsoft 尝试限制需要验证的请求。例如,他们不检查对静态文件的请求。此外,跳过未绑定到路由的参数。由于不能在路由参数键中使用具有潜在危险的字符,因此我们无需担心验证这些字符。

此外,正如您所指出的,对于无效的路径字符,也无需验证参数 values(例如 cookie 值)。集合值仍将通过基本 IsValidRequestString() 逻辑评估是否存在 其他 潜在危险字符串(例如 &lt;script)。

【讨论】:

这个怎么样? owasp.org/www-community/ASP-NET_Request_Validation @markzzz:我玩弄了覆盖RequestValidator。我遇到的挑战是例外情况,例如~/http:/~/&lt; 被抛出之前任何自定义请求验证器(或异常过滤器)被评估,因此直接转到您的 Application_Error() 处理程序。我怀疑这确实是这里的核心问题。我不确定这些正在评估中的何处,但它们似乎处于相对较低的水平。不幸的是,这让我回到了上面的答案。 如果你在web.config上设置&lt;httpRuntime targetFramework="4.6.1" requestPathInvalidCharacters=""/&gt;,它会在Application_Error()之前调用。然后,在内部,您可以管理它们,将“原始”模式指定为匹配点。这些应该是 .NET 检查的字符:docs.microsoft.com/en-us/dotnet/api/…(您可以在完成自定义验证后设置)。你怎么看? @markzzz:这是一个聪明的解决方法!我喜欢这个,因为它通过RequestValidator 统一了所有请求验证,允许您简单地处理标准HttpRequestValidationExceptionRequestValidator 仍然在 MVC 全局异常过滤器之前调用,但这很容易通过 Application_Error() 进行管理。这可能会通过将低级别验证推到管道中而增加一些开销,但这可能是可靠控制此错误的可接受折衷。我已经用经过测试的代码更新了我的答案——不过,在这一点上,功劳应该归你所有。 并非如此。如果现在用不需要的字符过滤“所有数据”,甚至是 cookie。我只需要过滤网址...该死的,这很成问题:(

以上是关于如何处理“从客户端检测到潜在危险的 Request.Form 值”?的主要内容,如果未能解决你的问题,请参考以下文章

从客户端检测到潜在危险的 Request.Form 值

从客户端检测到潜在危险的 Request.Path 值 (&)

当 GoogleBot 访问时,“从客户端检测到潜在危险的 Request.Path 值”,但不是通过直接链接

将 html 标记从 jquery 发布调用发送到 asp.net 页面时,从客户端检测到潜在危险的 Request.QueryString 值

处理“潜在危险的 Request.Form 值...”

弗尤博客