Blocking SQL injection using IIS URL Rewrite
We have had quite a few conversations about SQL injection on my blog, including Filtering SQL Injection from Classic ASP and Using Rules Configuration in UrlScan 3.0 to filter SQL injection. One of the shortcomings that we talked about was that UrlScan is not as flexible as some users want it to be since it does not have the ability to use regular expressions. Well the story changes quite a bit with IIS URL Rewrite module, that is capable of doing request and response rewriting based on regular expressions. For those weighing between URL Rewrite and UrlScan, URL Rewrite has more flexibility but UrlScan is a lot more performant, so choose depending on your needs and resources.
I have seen a lot of articles crop up with increasingly complex and voluminous rules for this, so I wanted to present something a little more simplified for folks to use. Thanks to Bala from the SQL Server Security team (who has written excellent MSDN documentation on preventing SQL injections in ASP) there is a simpler rule to use that will catch quite a few of the variants without any false positives for any valid requests that I have seen so far. Most of the widespread automated SQL injection attacks use a DECLARE->CAST->EXEC approach to executing their injection. If I were to just put 'CAST' in a deny list I would hit a lot of false-positives, e.g. if my Url contained the word 'casting'.By requiring a Declare ... Cast ... Exec structure we can drastically reduce the chances of a false-positive.
Here is the Regular Expression used:
[dD][\%]*[eE][\%]*[cC][\%]*[lL][\%]*[aA][\%]*[rR][\%]*[eE][\s\S]*[@][a-zA-Z0-9_]+[\s\S]*[nN]*[\%]*[vV][\%]*[aA][\%]*[rR][\%]*[cC][\%]*[hH][\%]*[aA][\%]*[rR][\s\S]*[eE][\%]*[xX][\%]*[eE][\%]*[cC][\s\S]*
Notice the the groupings in the brackets towards the beginning spell out DECLARE and that towards the end spell out EXEC. That should give you a good idea of how this regex is expected to work. To add this validation to the REQUEST_URI you could use configuration like that below in a web.config file.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Filter SQL injection" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{REQUEST_URI}" pattern="[dD][\%]*[eE][\%]*[cC][\%]*[lL][\%]*[aA][\%]*[rR][\%]*[eE][\s\S]*[@][a-zA-Z0-9_]+[\s\S]*[nN]*[\%]*[vV][\%]*[aA][\%]*[rR][\%]*[cC][\%]*[hH][\%]*[aA][\%]*[rR][\s\S]*[eE][\%]*[xX][\%]*[eE][\%]*[cC][\s\S]*" />
</conditions>
<action type="AbortRequest" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
You can change the <match url> directive above to \.as[p|px] if you want to apply the filtering rule to .asp and .aspx pages only.
Update: The SQL server security team has a more detailed blog entry on this that you can refer to.