IIS 的请求过滤模块本质上是一道部署在应用层之前的防火墙。它的核心价值在于,在恶意请求到达你的 Web 应用代码之前,直接将其拦截,从而减少服务器资源消耗并封堵大量已知的注入与遍历攻击。很多人配置完网站后就默认运行,这往往留下了高危隐患,因为默认配置通常允许了过于宽泛的 URL 字符集和文件扩展名。我们要做的,就是根据业务需求,把“允许”变为“拒绝”,实施最小权限原则。

请求过滤的配置主要有两种途径,一种是使用 IIS 管理器图形界面,另一种是直接编辑 web.config 文件。对于需要批量部署或版本控制的场景,直接修改配置文件是更精准和高效的方式。下面我们直接切入具体的防御配置,所有操作均围绕 system.webServer 节点下的 security/requestFiltering 展开。

拒绝未映射的文件扩展名

攻击者常常通过尝试访问 .asax、.cs、.config、.bak 等敏感文件来获取源代码或配置信息。如果这些扩展名没有映射给 ASP.NET 处理程序,IIS 静态文件处理程序可能会直接将其内容返回给客户端。我们必须显式拒绝这些高危扩展名,即便它们没有被映射。

<configuration>
  <system.webServer>
    <security>
      <requestFiltering>
        <fileExtensions allowUnlisted="false" applyToWebDAV="true">
          <add fileExtension=".aspx" allowed="true" />
          <add fileExtension=".ashx" allowed="true" />
          <add fileExtension=".asmx" allowed="true" />
          <add fileExtension=".css" allowed="true" />
          <add fileExtension=".js" allowed="true" />
          <add fileExtension=".jpg" allowed="true" />
          <add fileExtension=".png" allowed="true" />
          <add fileExtension=".gif" allowed="true" />
          <add fileExtension=".ico" allowed="true" />
        </fileExtensions>
      </requestFiltering>
    </security>
  </system.webServer>
</configuration>

这个配置的关键在于 allowUnlisted="false"。一旦设置,IIS 将只允许列表中显式声明为 allowed="true" 的扩展名。任何未列出的扩展名,如 .zip、.log 或 .bak,都将被服务器直接拒绝,返回 404.7 状态码。applyToWebDAV="true" 则确保该规则同样作用于 WebDAV 请求,防止绕过。如果你的站点需要提供下载文件,请务必把对应的文件扩展名加进去,否则用户将无法下载。

隐藏响应头中的服务器信息

请求过滤模块还能移除响应头中泄露的服务器版本信息。虽然这不能直接阻止攻击,但能显著增加自动化扫描工具的信息收集难度。我们通过 removeServerHeader 属性来移除 Server 头。

<requestFiltering removeServerHeader="true">
  <!-- 其他过滤规则 -->
</requestFiltering>

设置后,IIS 将不再输出 "Server: Microsoft-IIS/10.0" 这样的头部。但请注意,如果你的应用自身在代码中输出了自定义的 X-Powered-By 或其他头部,你还需要在 IIS 的 HTTP 响应头模块中单独移除它们。

限制 URL 和查询字符串的长度与字符

过长的 URL 是缓冲区溢出攻击的常见载体,而包含特殊字符的 URL 则可能用于 SQL 注入或跨站脚本攻击。我们需要对 URL、查询字符串以及 HTTP 动词进行严格的长度和字符集限制。

<requestFiltering>
  <requestLimits maxAllowedContentLength="30000000" 
                 maxUrl="4096" 
                 maxQueryString="2048" 
                 maxAllowedSegments="64" />
  <denyUrlSequences>
    <add sequence=".." />
    <add sequence="--" />
    <add sequence=";" />
    <add sequence="//" />
  </denyUrlSequences>
  <denyQueryStringSequences>
    <add sequence="<script" />
    <add sequence="declare " />
    <add sequence="xp_" />
  </denyQueryStringSequences>
</requestFiltering>

maxAllowedContentLength 限制上传内容的大小,单位是字节,这里设置为约 30MB,你需要根据业务实际调整。maxUrl 和 maxQueryString 分别限制 URL 路径和查询字符串的长度,4096 和 2048 是较为合理的起点。denyUrlSequences 中直接禁止了双点(..)用于路径遍历,双横线(--)用于 SQL 注释注入,分号(;)用于参数污染。denyQueryStringSequences 则针对查询字符串中的脚本标签和 SQL 关键字进行拦截。这种基于关键字的过滤简单粗暴,但非常有效,能拦截绝大多数自动化的扫描攻击。

限制 HTTP 动词

对于大多数内容型网站,GET、POST 和 HEAD 就足够了。PUT、DELETE、TRACE 和 OPTIONS 等方法往往被用于漏洞探测或 WebDAV 利用。通过限制动词,可以关闭不必要的攻击面。

<requestFiltering>
  <verbs allowUnlisted="false" applyToWebDAV="true">
    <add verb="GET" allowed="true" />
    <add verb="POST" allowed="true" />
    <add verb="HEAD" allowed="true" />
  </verbs>
</requestFiltering>

同样,allowUnlisted="false" 确保任何未列出的动词都会被拒绝,返回 405 方法不允许。如果你的应用是 RESTful API,需要 PUT 或 DELETE,请务必在此处添加。TRACE 方法尤其危险,因为它可能导致跨站追踪攻击,应始终禁用。

过滤特定 URL 片段

有时我们需要对特定路径实施更精细的控制。比如,禁止访问 /admin 目录下的所有内容,或者禁止访问包含特定特征的 URL。这可以通过 denyUrlSequences 和隐藏段配置来实现。

<requestFiltering>
  <hiddenSegments applyToWebDAV="true">
    <add segment="App_Data" />
    <add segment="bin" />
    <add segment="App_Code" />
    <add segment="App_GlobalResources" />
    <add segment="App_LocalResources" />
    <add segment="App_Browsers" />
    <add segment="App_WebReferences" />
  </hiddenSegments>
  <denyUrlSequences>
    <add sequence="/admin/" />
    <add sequence="/backup/" />
    <add sequence="/web.config" />
  </denyUrlSequences>
</requestFiltering>

hiddenSegments 会阻止对这些路径的直接访问,即使它们物理存在于磁盘上。denyUrlSequences 则更直接,只要 URL 中出现该序列就拒绝。注意,/admin/ 的写法会匹配任何包含该路径的请求,包括 /admin/login.aspx,从而保护整个管理后台。如果你需要开放管理后台,应移除该规则,转而依赖应用程序自身的身份验证。

使用请求过滤规则进行高级拦截

IIS 的请求过滤还支持自定义过滤规则,这允许我们基于正则表达式或特定条件对请求的任意部分进行检查。比如,我们可以创建规则来拦截 User-Agent 为空的请求,或者拦截包含特定扫描器特征的请求。

<requestFiltering>
  <filteringRules>
    <filteringRule name="BlockEmptyUserAgent" scanUrl="false" scanQueryString="false" scanHeaders="true">
      <scanHeaders>
        <clear />
        <add requestHeader="User-Agent" />
      </scanHeaders>
      <appliesTo>
        <clear />
        <add fileExtension=".aspx" />
        <add fileExtension=".ashx" />
      </appliesTo>
      <denyStrings>
        <add string="" />
      </denyStrings>
    </filteringRule>
    <filteringRule name="BlockSQLInjectionURI" scanUrl="true" scanQueryString="false" scanHeaders="false">
      <denyStrings>
        <add string="select " />
        <add string="union " />
        <add string="insert " />
        <add string="drop " />
        <add string="update " />
        <add string="delete " />
        <add string="exec " />
        <add string="1=1" />
      </denyStrings>
    </filteringRule>
  </filteringRules>
</requestFiltering>

第一个规则 BlockEmptyUserAgent 只扫描请求头中的 User-Agent,如果发现其值为空字符串,则拒绝请求,并且该规则仅应用于 .aspx 和 .ashx 动态文件,避免误伤静态资源请求。第二个规则 BlockSQLInjectionURI 专门扫描 URL 路径,查找常见的 SQL 注入关键字。注意,这种基于关键字的过滤可能会产生误报,比如你的 URL 中恰好包含 "update" 这个词。因此,部署后需要密切监控日志,根据实际情况调整关键字列表。scanUrl、scanQueryString 和 scanHeaders 这三个布尔属性允许你精确控制规则的扫描范围,以优化性能。

处理被拦截请求的默认行为

当请求被请求过滤模块拦截时,IIS 会返回相应的 HTTP 状态码,如 404(未找到)、404.7(文件扩展名拒绝)、404.11(URL 序列拒绝)等。这些状态码会暴露你的安全策略。你可以通过自定义错误页面来统一处理这些响应,避免信息泄露。

<httpErrors errorMode="Custom" existingResponse="Replace">
  <remove statusCode="404" subStatusCode="7" />
  <error statusCode="404" subStatusCode="7" path="/errors/notfound.html" responseMode="File" />
  <remove statusCode="404" subStatusCode="11" />
  <error statusCode="404" subStatusCode="11" path="/errors/notfound.html" responseMode="File" />
</httpErrors>

这样配置后,无论是文件扩展名被拒还是 URL 序列被拒,用户都只会看到一个统一的 404 页面,攻击者无法从中判断是文件不存在还是被安全策略拦截。这是一种纵深防御的思路,增加了攻击者的信息收集成本。

日志监控与规则调优

配置完规则后,工作只完成了一半。你必须持续监控 IIS 日志中由请求过滤模块产生的子状态码。通过分析这些日志,你可以发现哪些规则产生了误报,哪些攻击尝试最为频繁。例如,如果大量合法请求因为 URL 中包含 "update" 被拦截,你就需要从 denyStrings 中移除该关键字,或者将其修改为更精确的匹配模式。IIS 日志中的 sc-win32-status 和 sc-substatus 字段是诊断请求过滤行为的关键。定期审查这些日志,根据业务流量不断打磨你的过滤规则集,才能让安全防护既严密又不影响用户体验。一个长期无人维护的严格规则集,最终往往会被业务团队要求全盘关闭,反而失去了所有防护。

请求过滤是 IIS 安全配置中最基础也最强大的防线之一。它不能替代应用层的输入验证和参数化查询,但能作为第一道闸门,过滤掉绝大部分噪音和自动化攻击。正确配置后,你的应用服务器将只接收符合预期的、格式规范的请求,这本身就消除了大量潜在风险。