使用 IIS url 重写来防止 SQL 注入

Using IIS url rewrite to protect against SQL injection

我们在服务器上使用各种 CMS(Wordpress、Joomla),因此很多代码是第三方的,因此我们无法控制质量。虽然我们总是让所有内容保持最新,但我们最近有一个网站被黑了。

为了尝试防止这种情况在未来发生,我已将 URL 重写规则添加到 web.config 文件中。但我有几个问题:

  1. 我应该使用 RequestFiltering 而不是 Query_String 来检测注入吗?还是没有区别?

  2. web.config 是由 IIS 缓存还是像 Apache .htaccess 一样在每个请求上查询?如果是这样,这会消耗性能吗?

  3. 我有没有错过任何可能的攻击?

代码...

<rule name="Injection Blocking">
     <match url="^(.*)$" ignoreCase="false" />
     <conditions logicalGrouping="MatchAny">
       <add input="{HTTP_USER_AGENT}" pattern="(havij|libwww-perl|wget|python|nikto|curl|scan|java|winhttp|clshttp|loader)" />
       <add input="{HTTP_USER_AGENT}" pattern="(%0A|%0D|%27|%3C|%3E|%00)" />
       <add input="{HTTP_USER_AGENT}" pattern="(;|&lt;|>|'|&quot;|\)|\(|%0A|%0D|%22|%27|%28|%3C|%3E|%00).*(libwww-perl|wget|python|nikto|curl|scan|java|winhttp|HTTrack|clshttp|archiver|loader|email|harvest|extract|grab|miner)" />
       <add input="{THE_REQUEST}" pattern="(\?|\*|%2a)+(%20+|\s+|%20+\s+|\s+%20+|\s+%20+\s+)HTTP(:/|/)" />
       <add input="{THE_REQUEST}" pattern="etc/passwd" />
       <add input="{THE_REQUEST}" pattern="cgi-bin" />
       <add input="{THE_REQUEST}" pattern="(%0A|%0D|\r|\n)" />
       <add input="{URL}" pattern="owssvr\.dll" />
       <add input="{HTTP_REFERER}" pattern="(%0A|%0D|%27|%3C|%3E|%00)" />
       <add input="{HTTP_REFERER}" pattern="\.opendirviewer\." />
       <add input="{HTTP_REFERER}" pattern="users\.skynet\.be.*" />
       <add input="{QUERY_STRING}" pattern="[a-zA-Z0-9_]=http://" />
       <add input="{QUERY_STRING}" pattern="[a-zA-Z0-9_]=(\.\.//?)+" />
       <add input="{QUERY_STRING}" pattern="[a-zA-Z0-9_]=/([a-z0-9_.]//?)+" />
       <add input="{QUERY_STRING}" pattern="\=PHP[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" />
       <add input="{QUERY_STRING}" pattern="(\.\./|%2e%2e%2f|%2e%2e/|\.\.%2f|%2e\.%2f|%2e\./|\.%2e%2f|\.%2e/)" />
       <add input="{QUERY_STRING}" pattern="ftp\:" />
       <add input="{QUERY_STRING}" pattern="http\:" />
       <add input="{QUERY_STRING}" pattern="https\:" />
       <add input="{QUERY_STRING}" pattern="\=\|w\|" />
       <add input="{QUERY_STRING}" pattern="^(.*)/self/(.*)$" />
       <add input="{QUERY_STRING}" pattern="^(.*)cPath=http://(.*)$" />
       <add input="{QUERY_STRING}" pattern="(\&lt;|%3C).*script.*(\>|%3E)" />
       <add input="{QUERY_STRING}" pattern="(&lt;|%3C)([^s]*s)+cript.*(>|%3E)" />
       <add input="{QUERY_STRING}" pattern="(\&lt;|%3C).*embed.*(\>|%3E)" />
       <add input="{QUERY_STRING}" pattern="(&lt;|%3C)([^e]*e)+mbed.*(>|%3E)" />
       <add input="{QUERY_STRING}" pattern="(\&lt;|%3C).*object.*(\>|%3E)" />
       <add input="{QUERY_STRING}" pattern="(&lt;|%3C)([^o]*o)+bject.*(>|%3E)" />
       <add input="{QUERY_STRING}" pattern="(\&lt;|%3C).*iframe.*(\>|%3E)" />
       <add input="{QUERY_STRING}" pattern="(&lt;|%3C)([^i]*i)+frame.*(>|%3E)" />
       <add input="{QUERY_STRING}" pattern="base64_encode.*\(.*\)" />
       <add input="{QUERY_STRING}" pattern="base64_(en|de)code[^(]*\([^)]*\)" />
       <add input="{QUERY_STRING}" pattern="GLOBALS(=|\[|\%[0-9A-Z]{0,2})" ignoreCase="false" />
       <add input="{QUERY_STRING}" pattern="_REQUEST(=|\[|\%[0-9A-Z]{0,2})" ignoreCase="false" />
       <add input="{QUERY_STRING}" pattern="^.*(\(|\)|&lt;|>|%3c|%3e).*" />
       <add input="{QUERY_STRING}" pattern="^.*(\x00|\x04|\x08|\x0d|\x1b|\x20|\x3c|\x3e|\x7f).*" />
       <add input="{QUERY_STRING}" pattern="(NULL|OUTFILE|LOAD_FILE)" ignoreCase="false" />
       <add input="{QUERY_STRING}" pattern="(\.{1,}/)+(motd|etc|bin)" />
       <add input="{QUERY_STRING}" pattern="(localhost|loopback|127\.0\.0\.1)" />
       <add input="{QUERY_STRING}" pattern="(&lt;|>|'|%0A|%0D|%27|%3C|%3E|%00)" />
       <add input="{QUERY_STRING}" pattern="concat[^\(]*\(" />
       <add input="{QUERY_STRING}" pattern="union([^s]*s)+elect" />
       <add input="{QUERY_STRING}" pattern="union([^a]*a)+ll([^s]*s)+elect" />
       <add input="{QUERY_STRING}" pattern="\-[sdcr].*(allow_url_include|allow_url_fopen|safe_mode|disable_functions|auto_prepend_file)" />
       <add input="{QUERY_STRING}" pattern="(;|&lt;|>|'|&quot;|\)|%0A|%0D|%22|%27|%3C|%3E|%00).*(/\*|union|select|insert|drop|delete|update|cast|create|char|convert|alter|declare|order|script|set|md5|benchmark|encode)" />
       <add input="{QUERY_STRING}" pattern="(sp_executesql)" />
    </conditions>
   <action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Forbidden" />
</rule>

本质上,您是在尝试编写自己的基于黑名单的原始迷你 WAF(Web 应用程序防火墙)。 根据我的经验,仅仅根据黑名单原始签名来尝试猜测所有可能的攻击是没有意义的,这是一场你赢不了的游戏。 例如,您尝试通过阻止脚本和 Iframe 标记来阻止 XSS 可以通过多种方式轻松绕过,其中一些就像 <img src='a' onerror=alert('xss')/> 一样简单,我什至没有提到小写大写-case regex 规避几乎可以绕过你所有的反 SQL 注入尝试。

Web应用防火墙是价值数百万美元的产品,他们有一小部分调查人员试图更新他们的签名,并且在行为分析和基于白名单的学习模式方面投入了大量精力,从而大大提高了安全级别,而且您无法真正将您的出色尝试与他们的产品进行比较。 你可能会阻止脚本小子,让专业黑客多出点汗,但你不会阻止基于这种防御的攻击者。

我的建议是,与其尝试自己动手,不如购买一种主要的 WAF(F5、Imperva),或者如果您负担不起,只需搜索显然具有 IIS 的合适的 free IIS based WAF for you and install it. It would probably do a better job than you - no offend. Speaking of free WAFs, I'm familiar with the good old ModSecurity版本也一样。

祝你好运!