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

问题描述 投票:75回答:4

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

/产品/标签/为+家庭

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

HTTP错误404.11 - 未找到

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

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

  <system.webServer>
    <security>
      <requestFiltering allowDoubleEscaping="true" />
    </security>
  </system.webServer>

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

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

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

asp.net asp.net-mvc asp.net-mvc-3 iis iis-7
4个回答
51
投票

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

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

例如,如果要基于action方法的id参数构建动态SQL查询,如下所示:

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

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

/product/tags/1%27;drop%20table%20Tags;%20--

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

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


2
投票

Security Risk

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

/product/tags/for+families --> /product/tags/for%2Bfamilies --> /product/tags/for%252Bfamilies

假设有专门针对/product/tags/for+families的安全控制措施。 /product/tags/for%252Bfamilies的请求到达,虽然上述安全控制未选中,但RFC2396是相同的资源。我使用了安全控件的通用术语,因为它们可能是需要经过身份验证的用户,检查SQLi等的任何内容。

Why Does IIS Block?

加号(+)是每个 reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," 的保留字符:

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

How IIS blocks characters in URLs

Wade Hilmo有一篇很棒的帖子,名为allowDoubleEscaping=true。提供了大量信息和背景。专用于加号的部分如下:

所以allowDoubleEscaping / VerifyNormalization看起来非常简单。为什么我说这会造成混乱?问题是当URL中出现“+”字符时。 '+'字符似乎没有被转义,因为它不涉及'%'。此外,RFC 2396将其注释为保留字符,当它以转义形式(%2b)时可以包含在URL中。但是如果将allowDoubleEscaping设置为其默认值false,我们将以转义形式阻止它。其原因是历史性的:早在HTTP的早期,“+”字符被认为是空格字符的简写。一些规范化器,当给定包含“+”的URL时,会将其转换为空格。出于这个原因,我们认为“+”在URL中是非规范的。我无法找到任何引用这种“+”处理的RFC的引用,但网上有很多引用将它作为历史行为来讨论。

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

Solution

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

  1. allowDoubleEscaping=true - 这将允许您的整个网站/应用程序双重逃避。根据内容,至少可以说这是不可取的。以下命令将设置appcmd.exe set config "Default Web Site" -section:system.webServer/security/requestFiltering /allowDoubleEscaping:True alwaysAllowedUrls
  2. /product/tags/for+families - 请求过滤提供白名单方法。通过将该URL路径添加到alwaysAllowedUrls,任何其他请求筛选设置都不会检查该请求,并继续在IIS请求管道中。这里的问题是请求过滤不会检查以下请求: 请求限制:maxContentLength,maxUrl,maxQueryString 动词 查询 - 不会检查查询字符串参数 双重逃脱 高位字符 请求过滤规则 请求标头限制 以下命令将alwaysAllowedUrls添加到默认网站上的appcmd.exe set config "Default Web Site" -section:system.webServer/security/requestFiltering /+"alwaysAllowedUrls.[url='/product/tags/for+families']" 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; }
  3. 重命名 - 是的,只需重命名文件/文件夹/控制器/等。如果可能的话。这是最简单的解决方案。

1
投票

我为此做了一个工作。所以当你想把encripted字符串放在(IIS)的url中时你必须从dirty清除它:{“;”,“/”,“?”,“:”,“@”,“&”,“ =“,”+“,”$“,”,“};当你想要它并再次使用它时,你必须在描述之前再次弄脏它(以获得想要的结果)。

这是我的代码,我希望它有助于某人:

HttpUtility.UrlPathEncode

0
投票

所以当我从MVC应用程序调用API时遇到了这个问题。我修改了自己的路径,而不是打开安全漏洞。

首先,我建议不要禁用此设置。修改应用程序/资源的设计更合适(例如,编码路径,在标题或正文中传递数据)。

虽然这是一篇较旧的帖子,但我想我会分享如何通过在System.Web中使用RestSharp方法调用API来解决此错误。

我使用var tags = new[] { "for", "family" }; var apiRequest = new RestRequest($"product/tags/{HttpUtility.UrlPathEncode(string.Join("+", tags))}"); 进行调用,所以我的例子是使用RestRequest:

SqlParameter

这会产生一个等于的路径:

/产品/标签/用于%2Bfamilies

另外请注意,不要根据用户的输入构建动态查询。你应该总是使用qazxswpoi。此外,从安全角度来看,使用适当的编码返回值以防止注入攻击非常重要。

〜干杯

© www.soinside.com 2019 - 2024. All rights reserved.