url中的双转义序列:请求过滤模块配置为拒绝包含双转义序列的请求

tug*_*erk 78 asp.net iis asp.net-mvc iis-7 asp.net-mvc-3

在我的ASP.NET MVC应用程序上,我正在尝试实现如下的URL:

/产品/标签/为+家庭

当我尝试使用默认配置运行我的应用程序时,我收到404.11响应代码的消息:

HTTP错误404.11 - 未找到

请求过滤模块被配置为拒绝包含双转义序列的请求.

我可以通过在web.config中实现以下代码来解决此错误:

  <system.webServer>
    <security>
      <requestFiltering allowDoubleEscaping="true" />
    </security>
  </system.webServer>
Run Code Online (Sandbox Code Playgroud)

所以,现在我没有得到任何404.11.

我想知道的是,我正在用这种实现打开什么样的安全漏洞.

顺便说一句,我的应用程序正在.Net Framework 4.0运行IIS 7.5.

And*_*lad 51

您可能打开的安全漏洞与代码注入有关 - HTML注入,JavaScript注入或SQL注入.

默认设置通过不允许常用注入策略工作来半保护地免受攻击.您删除的默认安全性越多,您就越需要考虑通过URL提供的输入,GET请求查询字符串,POST请求数据,HTTP标头等等...

例如,如果要基于id操作方法的参数构建动态SQL查询,请执行以下操作:

public ActionResult Tags(string id)
{
    var sql = "SELECT * FROM Tags Where tagName = '" + id + "'";
    // DO STUFF...
}
Run Code Online (Sandbox Code Playgroud)

(...这不是一个好主意),.NET框架实施的默认保护可能会阻止一些更危险的情况,例如请求此URL的用户:

/product/tags/1%27;drop%20table%20Tags;%20--
Run Code Online (Sandbox Code Playgroud)

整个想法是将网址的每个部分和行动方法的其他输入视为可能的威胁.默认安全设置确实为您提供了一些保护.您更改的每个默认安全设置都会打开您需要手动处理的更多潜在错误.

我假设您没有以这种方式构建SQL查询.但是,当您将用户输入存储在数据库中,然后显示它们时,会出现更多偷偷摸摸的东西.恶意用户可以在您的数据库中存储未编码的JavaScript或HTML,这反过来会威胁到您系统的其他用户.


use*_*464 8

安全风险

该设置allowDoubleEscaping仅适用于path(cs-uri-stem) 并且最好由OWASP Double Encoding解释。该技术用于通过对请求进行两次 URL 编码来绕过安全控制。以您的网址为例:

/product/tags/for+families --> /product/tags/for%2Bfamilies --> /product/tags/for%252Bfamilies
Run Code Online (Sandbox Code Playgroud)

假设有专门针对/product/tags/for+families. 到达的请求/product/tags/for%252Bfamilies是相同的资源,但未受到上述安全控制的检查。我使用了安全控制的广义术语,因为它们可以是任何东西,例如需要经过身份验证的用户、检查 SQLi 等。

为什么 IIS 会阻塞?

加号 (+) 是每个RFC2396的保留字符:

许多 URI 包括由某些特殊字符组成或由某些特殊字符分隔的组件。这些字符被称为“保留”,因为它们在 URI 组件中的使用仅限于它们的保留用途。如果 URI 组件的数据与保留目的冲突,则必须在形成 URI 之前对冲突数据进行转义。

  reserved    = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
                "$" | ","
Run Code Online (Sandbox Code Playgroud)

Wade Hilmo 有一篇出色的文章,标题为IIS 如何阻止 URL 中的字符。提供了很多信息和背景。加号部分具体如下:

所以allowDoubleEscaping/VerifyNormalization 看起来很简单。为什么我说它会引起混乱?问题在于 URL 中出现“+”字符时。'+' 字符似乎没有被转义,因为它不涉及 '%'。此外,RFC 2396 将其标记为保留字符,当 URL 为转义形式 (%2b) 时,可以将其包含在 URL 中。但是当allowDoubleEscaping 设置为其默认值false 时,即使以转义形式我们也会阻止它。这是历史原因:早在 HTTP 的早期,'+' 字符被认为是空格字符的简写。某些规范化程序在给定包含“+”的 URL 时会将其转换为空格。出于这个原因,我们认为“+”在 URL 中是非规范的。我无法找到任何引用 RFC 的引用,该 RFC 调用了这种“+”处理,

根据我自己的经验,我知道当 IIS 记录请求空间时,会用加号代替。名称中有加号可能会在解析日志时造成混淆。

解决方案

有三种方法可以解决这个问题,还有两种方法可以继续使用加号。

  1. allowDoubleEscaping=true- 这将允许您的整个网站/应用程序进行双重转义。根据内容,这至少可以说是不受欢迎的。以下命令将设置allowDoubleEscaping=true.

    appcmd.exe set config "Default Web Site" -section:system.webServer/security/requestFiltering /allowDoubleEscaping:True
    
    Run Code Online (Sandbox Code Playgroud)
  2. alwaysAllowedUrls- 请求过滤提供白名单方法。通过将该 URL 路径添加到 alwaysAllowedUrls,该请求将不会被任何其他请求过滤设置检查并在 IIS 请求管道中继续。这里的问题是请求过滤不会检查请求:

    • 请求限制:maxContentLength、maxUrl、maxQueryString
    • 动词
    • 查询 - 不会检查查询字符串参数
    • 双逃
    • 高位字符
    • 请求过滤规则
    • 请求头限制

    以下命令将添加/product/tags/for+familiesalwaysAllowedUrls默认网站上。

    appcmd.exe set config "Default Web Site" -section:system.webServer/security/requestFiltering /+"alwaysAllowedUrls.[url='/product/tags/for+families']"
    
    Run Code Online (Sandbox Code Playgroud)
  3. 重命名- 是的,只需重命名文件/文件夹/控制器/等。如果可能的话。这是最简单的解决方案。

  • @paulsm4,正如帖子所述,“将allowDoubleEscaping设置为其默认值 false,我们将阻止[+],即使是转义形式。”我用“EscapeUriString”和“EscapeDataString”测试了这一点,并且转义的“+”仍然如此不通过。 (3认同)

mar*_*ibe 5

我已经为此做了一个工作。因此,当您想将已加密的字符串放入(IIS)的 url 中时,您必须将其清除干净:{ ";"、"/"、"?"、":"、"@"、"&"、" =", "+", "$", "," }; 并且当您想对其进行解密并再次使用它时,您必须在解密之前再次将其弄脏(以获得想要的结果)。

这是我的代码,我希望它可以帮助某人:

 public static string cleanUpEncription(string encriptedstring)
        {
            string[] dirtyCharacters = { ";", "/", "?", ":", "@", "&", "=", "+", "$", "," };
            string[] cleanCharacters = { "p2n3t4G5l6m","s1l2a3s4h","q1e2st3i4o5n" ,"T22p14nt2s", "a9t" , "a2n3nd","e1q2ua88l","p22l33u1ws","d0l1ar5","c0m8a1a"};

            foreach (string dirtyCharacter in dirtyCharacters)
            {
                encriptedstring=encriptedstring.Replace(dirtyCharacter, cleanCharacters[Array.IndexOf(dirtyCharacters, dirtyCharacter)]);
            }
            return encriptedstring;
        }

        public static string MakeItDirtyAgain(string encriptedString)
        {
            string[] dirtyCharacters = { ";", "/", "?", ":", "@", "&", "=", "+", "$", "," };
            string[] cleanCharacters = { "p2n3t4G5l6m", "s1l2a3s4h", "q1e2st3i4o5n", "T22p14nt2s", "a9t", "a2n3nd", "e1q2ua88l", "p22l33u1ws", "d0l1ar5", "c0m8a1a" };
            foreach (string symbol in cleanCharacters)
            {
                encriptedString = encriptedString.Replace(symbol, dirtyCharacters[Array.IndexOf(cleanCharacters,symbol)]);
            }
            return encriptedString;
        }
Run Code Online (Sandbox Code Playgroud)