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


86

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

/ product / tags / for + familys

当我尝试使用默认配置运行我的应用程序时,我收到带有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


是否可以改为使用所需资源/product/tags/for%20families?然后,您可以找到包含空格的ID的解决方法。还是我完全不在这里?
2011年

我猜@atornblad有点偏离。我的问题是:我想知道的是,此实现将给我带来什么样的安全漏洞。
tugberk 2011年

5
IIS抛出“ +”字符,这是Microsoft的默认行为。
托德谢尔顿

Answers:


56

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

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

例如,如果要基于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--

整个想法是将URL的每个部分以及对操作方法的其他输入都视为可能的威胁。默认安全设置确实为您提供了一些保护。您更改的每个默认安全设置都会带来更多潜在的缺陷,需要您手动处理。

我假设您不是以这种方式构建SQL查询。但是,当您将用户输入存储在数据库中,然后再显示它们时,就会出现一些比较狡猾的事情。恶意用户可能会将JavaScript或HTML存储在您的数据库中,而这些JavaScript或HTML未经编码就出去了,这反过来又威胁到系统的其他用户。


6

安全风险

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

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

假设有专门用于的安全控制/product/tags/for+families/product/tags/for%252Bfamilies尽管没有被上述安全控件检查,但请求到达的资源是相同的。我使用了安全控制的广义术语,因为它们可以是诸如要求经过身份验证的用户,检查SQLi等之类的任何内容。

IIS为什么会阻止?

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

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

  reserved    = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
                "$" | ","

韦德·希尔莫(Wade Hilmo)的精彩文章标题为IIS如何阻止URL中的字符。提供了很多信息和背景。专门用于加号的部分如下:

因此allowDoubleEscaping / VerifyNormalization看起来非常简单。为什么我说这会引起混乱?问题是URL中出现“ +”字符时。'+'字符似乎没有被转义,因为它不包含'%'。另外,RFC 2396将其记为保留字符,当其以转义形式(%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
    
  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']"
    
  3. 重命名-是的,只需重命名文件/文件夹/控制器/等。如果可能的话。这是最简单的解决方案。


为了在使用IIS Express进行开发期间允许DoubleEscaping,这是我所做的:stackoverflow.com/q/56463044/381082
DeveloperDan

3

为此我做了一项工作。因此,当您想要将已编码的字符串放入(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;
        }

什么是pntGlm?
StuperUser

@StuperUser只是随机字符
马克·迪比

1
该字符串应该被base64编码,而不是使用这种替换技术。例如,基本身份验证用于base64对提交的凭据进行编码,因为它可能包含特殊/保留的字符。
user2320464

base64的问题是/是base64字符,并且可以中断路由
Garr Godfrey

1

因此,当我从MVC应用程序调用API时遇到了这种情况。我没有打开安全漏洞,而是修改了路径。

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

尽管这是一篇较旧的文章,但我认为如果您通过使用System.Web中的HttpUtility.UrlPathEncode方法从对API的调用中收到此错误,我想与您分享如何解决此错误。

我使用RestSharp进行呼叫,所以我的示例使用RestRequest:

var tags = new[] { "for", "family" };
var apiRequest = new RestRequest($"product/tags/{HttpUtility.UrlPathEncode(string.Join("+", tags))}");

产生的路径等于:

/ product / tags / for%2Bfamilies

另外,请不要基于用户的输入来构建动态查询。您应该始终使用SqlParameter。同样,从安全角度来看,使用适当的编码返回值以防止注入攻击也非常重要。

〜干杯


0

对加密的字符串进行编码:

return HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes("string"));

解码分离的加密字符串:

string x = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(id));
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.