We’ll
consider runtime protection to be any security solution that you can use
to detect, mitigate, or prevent SQL injection that is deployable
without recompiling the vulnerable application’s source code. The
solutions covered here are primarily software plug-ins for Web servers
and development frameworks (e.g., the .NET Framework, J2EE, PHP, etc.)
or techniques for leveraging/extending features of the Web or
application platform. Most of the software solutions we’ll discuss are
free and are available for download on the Internet. We will not cover
commercial products, although some may implement one or more of the
strategies and techniques discussed here.
Runtime protection is a valuable tool for mitigating and preventing exploitation of known
SQL injection vulnerabilities. Fixing the vulnerable source code is
always the ideal solution; however, the development effort required is
not always feasible, practical, cost-effective, or unfortunately a high
priority. Commercial off-the-shelf (COTS) applications are often
purchased in compiled format, which eliminates the possibility of fixing
the code. Even if uncompiled code is available for a COTS application,
customizations may violate support contracts and/or prevent the software
vendor from providing updates according to its normal release
cycle. Legacy applications close to retirement may not warrant the time
and effort required to make the necessary code changes. Organizations
may intend to make a code change, but don’t have the resources in the
near term to do so. These common scenarios highlight the need for
runtime protection in the form of virtual patching or band-aid solutions.
Even if the time and
resources are available for code fixes, runtime protection can still be a
valuable layer of security to detect or thwart exploitation of unknown
SQL injection vulnerabilities. If the application has never undergone
security code review or penetration testing, application owners might
not be aware of the vulnerabilities. There is also the threat of
“zero-day” exploit techniques as well as the latest and greatest SQL
injection worm traversing the Internet. In this way, runtime protection
is not just a reactive defense mechanism, but also a proactive step
toward comprehensively securing an application.
Although runtime protection
provides many benefits, you need to consider some of the costs that may
be involved. Depending on the solution, you should expect some level of
performance degradation (as you would expect anytime additional
processing and overhead are incurred). When evaluating a solution,
especially a commercial one, it is important to ask for documented
performance statistics. The other point of caution is that some runtime
solutions are more difficult to configure than others. If the solution
is overly complex, the time and resources spent getting it to work may
exceed the costs of actually fixing the code, or worse yet, you may
decide not to use it at all. Ensure that the solution you select comes
with detailed installation instructions, configuration examples, and
support (this doesn’t always mean paid support; some free solutions
provide good online support through forums). The key to getting the most
out of runtime protection is a willingness to learn the boundaries of
the technology and evaluate how it can best help you.
Web Application Firewalls
The most well-known
runtime solution in Web application security is the use of a Web
application firewall (WAF). A WAF is a network appliance or
software-based solution that adds security features to a Web
application. Specifically, we’re focusing on what WAFs can offer in
terms of SQL injection protection.
Software-based WAFs
are typically modules embedded into the Web server or application with
minimal configuration. Primary benefits of software-based WAFs are that
the Web infrastructure remains unchanged, and HTTP/HTTPS communications
are handled seamlessly because they run inside the Web- or
application-hosting process. Appliance-based WAFs don’t consume Web
server resources and they can protect multiple Web applications of
varying technologies. We will not cover network appliances any further,
although you can use some of the software solutions as a network
appliance when running on a Web server configured as a reverse proxy
server.
Need Help Evaluating a WAF?
Unfortunately, the
usefulness of WAFs is sometimes criticized; however, the criticism is
usually targeted at a specific implementation or commercial product.
Regardless of how you feel about WAFs, they will be a mainstay of Web
application security, especially as standard bodies such as the Payment
Card Industry (PCI) are endorsing them as an option to satisfy
Requirement 6.6.
To help evaluate the
various characteristics of a potential WAF solution, the Web Application
Security Consortium (WASC) published the “Web Application Firewall
Evaluation Criteria” (WAFEC) document (www.webappsec.org/projects/wafec/). This provides a good start point for beginning your evaluation of a WAF solution.
|
Using ModSecurity
The de facto standard for WAFs is the open source ModSecurity (http://www.modsecurity.org/www.modsecurity.org/).
ModSecurity is implemented as an Apache module; however, it can protect
virtually any Web application (even ASP and ASP.NET Web applications)
when the Apache Web server is configured as a reverse proxy. You can use
ModSecurity for attack prevention, monitoring, intrusion detection, and
general application hardening. We will use ModSecurity as the primary
example for discussing key features in detecting and preventing SQL
injection when using a WAF.
Configurable Rule Set
Web application
environments are unique, and WAFs must be highly configurable to
accommodate a wide variety of scenarios. The strength of ModSecurity is
its rule language, which is a combination of configuration directives
and a simple programming language applied to HTTP requests and
responses. The outcome is usually a specific action, such as allowing
the request to pass, logging the request, or blocking it. Before looking
at specific example, let’s first look at the generic syntax of the
ModSecurity directive SecRule, as shown in Figure 1.
Figure 1. Generic Syntax for SecRule
SecRule VARIABLE OPERATOR [ACTIONS]
|
The VARIABLE attribute tells ModSecurity where to look in the request or response, OPERATOR tells ModSecurity how to check this data, and ACTIONS determines what to do when a match occurs. The ACTIONS attribute is optional for a rule, as default global actions can be defined.
You can configure
ModSecurity rules to achieve a negative (i.e., blacklist) or positive
(i.e., whitelist) security model when handling HTTP request data. Let’s
look at Figure 2,
which is an actual blacklist SQL injection rule from the Generic
Attacks rule file (modsecurity_ crs_40_generic_attacks.conf ) of the
ModSecurity Core Rule Set. The following bullets walk you through the
rule and describe each configuration directive.
Figure 2. SQL Injection Rule from the Generic Attacks Rule File
# SQL injection
SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES
"(?:\b(?:(?:s(?:elect\b(?:.{1,100}?\b(?:(?:length|count|top)\b.{1,100}?\
bfrom|from\b.{1,100}?\bwhere)|.*?\b(?:d(?:ump\b.*\bfrom|ata_type)|(?:to_
(?:numbe|cha)|inst)r))|p_(?:(?:addextendedpro|sqlexe)c|(?:oacreat|prepar)e|execute
(?:sql)?|makewebtask)|ql_(?:longvarchar|variant))|xp_(?:reg(?:re(?:movemultistring|
ad)|delete(?:value|key)|enum(?:value|key)s|addmultistring|write)|e(?:xecresultset|
numdsn)|(?:terminat|dirtre)e|availablemedia|loginconfig|cmdshell|filelist|makecab|
ntsec)|u(?:nion\b.{1,100}?\bselect|tl_(?:file|http))|group\b.*\bby\b.{1,100}?\
bhaving|d(?:elete\b\W*?\bfrom|bms_java)|load\b\W*?\bdata\b.*\
binfile|(?:n?varcha|tbcreato)r)\b|i(?:n(?:to\b\W*?\b(?:dump|out)file|sert\b\W*?\
binto|ner\b\W*?\bjoin)\b|(?:f(?:\b\W*?\(\W*?\bbenchmark|null\b)|snull\b)\W*?\
()|a(?:nd\b ?(?:\d{1,10}|[\'\"][^=]{1,10}[\'\"]) ?[=<>>]+|utonomous_
transaction\b)|o(?:r\b ?(?:\d{1,10}|[\'\"][^=]{1,10}[\'\"])
?[=<>]+|pen(?:rowset|query)\b)|having\b ?(?:\d{1,10}|[\'\"][^=]{1,10}[\'\"])
?[=<>]+|print\b\W*?\@\@|cast\b\W*?\()|(?:;\W*?\b(?:shutdown|drop)|\@\@version)\b|'
(?:s(?:qloledb|a)|msdasql|dbo)')" \
"phase:2,capture,t:none,t:htmlEntityDecode,t:replaceComments,t:compressWhiteSpace,
t:lowercase,ctl:auditLogParts=+E,log,auditlog,msg:'SQL injection
Attack',id:'950001',tag:'WEB_ATTACK/SQL_INJECTION',logdata:'%{TX.0}',severity:
'CRITICAL'"
|
The rule is a security rule (SecRule), which is used to analyze data and perform actions based on the results.
The rule will be applied to the request body (phase:2). The specific targets for analysis on the request body are the request path (REQUEST_FILENAME), all request parameter values including POST data (ARGS), and request parameter names (ARGS_NAMES).
Each target is matched against the rather large regular expression pattern. Note that capturing (capture)
has been enabled for this regular expression. This means data that
matches parts of the pattern that are grouped with parentheses will be
later accessible with substitution variables 0 through 9.
Prior to the match, the request data is first subject to a number of translations(denoted by the t: syntax), to help decode evasive encodings employed by the attacker. The first is t:none, which clears all previously set translation functions from previous rules, and the last is t:lowercase,
which converts all characters to lowercase. The in-between translation
functions should be self-explanatory (refer to “Request Normalization”
for more information about data translations).
ModSecurity is instructed that for this rule the response body will also be logged (ctl:auditLogParts=+E).
Next, a successful match of the rule needs to be logged (log). This will go into the Apache error log file and the ModSecurity audit log (auditlog). A message indicating that this is an SQL injection attack is added to the rule (msg:’SQL injection Attack’) as well as a tag to classify the attack category in the log (tag:’WEB_ATTACK/ SQL_INJECTION’). Additionally, part of the matched data will also be logged (logdata: ’%{TX.0}’) via the capturing feature previously mentioned. All data is properly escaped before logging to avoid log-forging attacks.
Successful matches are considered critical (severity: ’CRITICAL’).
The rule is also assigned a unique ID (id:’950001’)
The ModSecurity
Core Rule Set includes blacklist rules for SQL injection and blind SQL
injection, which, depending on the application, could generate false
positives. Therefore, the default action for these rules is log
to avoid blocking legitimate requests out-of-the-box. This allows us to
weed out possible false positives without affecting normal application
behavior and tune the rules so that we are comfortable setting them to
block should we be faced with a zero-day threat. False positives are not
unique to ModSecurity; all WAFs will generate false positives if they
are not properly tuned. ModSecurity’s Core Rule Set default behavior is
preferable, as you want to monitor application behavior and tune rules
before turning on active protection in production environments. If you
are using ModSecurity to patch a known vulnerability, you can build a
custom rule set that achieves positive security (whitelisting).
Figure 3
shows a custom whitelist rule that you can use to apply a virtual patch
to a PHP script. Requests to script.php must contain one parameter
named statid and the
value must be a numerical value from one to three digits long. With
this patch in place, exploitation of an SQL injection vulnerability via
the statid parameter would not be possible.
Figure 3. Whitelist Rule to Patch a Vulnerable PHP Script
<Location /apps/script.php>
SecRule &ARGS "!@eq 1"
SecRule ARGS_NAMES "!^statid$"
SecRule ARGS:statID "!^\d{1,3}$"
</Location>
|
Request Coverage
SQL
injection protection can be very tricky for a WAF. Attack payloads can
manifest themselves virtually anywhere within an HTTP request, such as
the querystring, POST
data, cookies, custom and standard HTTP headers (e.g., Referer, Server,
etc.), or even parts of the URL path. ModSecurity can handle any of
these scenarios. Figure 4
is an example list of variables (i.e., targets for analysis) that
ModSecurity supports. This should give you an idea of the comprehensive
request-level protection that ModSecurity provides and that a WAF must
implement to adequately protect against SQL injection:
Figure 4. ModSecurity REQUEST Variables
REQUEST_BASENAME
REQUEST_BODY
REQUEST_COOKIES
REQUEST_COOKIES_NAMES
REQUEST_FILENAME
REQUEST_HEADERS
REQUEST_HEADERS_NAMES
REQUEST_LINE
REQUEST_METHOD
REQUEST_PROTOCOL
REQUEST_URI
REQUEST_URI_RAW
|
Request Normalization
Attack strings can be
encoded in a variety of ways to avoid detection and easily defeat simple
input validation filters. ModSecurity is capable of handling virtually
any complex encoding scenario, as it supports a wide variety of
transformation functions and can apply those functions multiple times
per rule and in any order. Figure 5 shows a list of transformation functions from the ModSecurity Reference Manual.
Figure 5. ModSecurity Transformation Functions
base64Decode
base64Encode
compressWhitespace
cssDecode
escapeSeqDecode
hexDecode
hexEncode
htmlEntityDecode
jsDecode
length
lowercase
md5
none
normalisePath
normalisePathWin
parityEven7bit
parityOdd7bit
parityZero7bit
removeNulls
removeWhitespace
replaceComments
replaceNulls
urlDecode
urlDecodeUni
urlEncode
sha1
trimLeft
trimRight
trim
|
If
for some reason built-in functions don’t meet your needs, you can build
custom transformation functions via ModSecurity’s support for the Lua
scripting language.
Response Analysis
Another key feature of a WAF
when it comes to mitigating SQL injection is the ability to suppress
key information leakage, such as detailed SQL error messages. Refer to Figure 6,
which is an actual outbound rule from the Outbound rule file
(modsecurity_crs_50_outbound.conf ) of the ModSecurity Core Rule Set.
Figure 6. SQL Errors Leakage Rule from the Outbound Rule File
# SQL Errors leakage
SecRule RESPONSE_BODY
"(?:\b(?:(?:s(?:elect list because it is not contained in (?:an aggregate function
and there is no|either an aggregate function or the) GROUP BY clause|upplied
argument is not a valid (?:(?:M(?:S |y)|Postgre)SQL|O(?:racle|DBC)))|S(?:yntax
error converting the \w+ value .*? to a column of data type|QL Server does not
exist or access denied)|Either BOF or EOF is True, or the current record has been
deleted(?:; the operation|\. Requested)|The column prefix .{0,50}? does not match
with a table name or alias name used in the query|Could not find server '\w+' in
sysservers\. execute sp_addlinkedserver)\b|Un(?:closed quotation mark before the
character string\b|able to connect to PostgreSQL server:)|(?:Microsoft OLE DB
Provider for .{0,30} [eE]rror |error '800a01b8)'|(?:Warning: mysql_connect\
(\)|PostgreSQL query failed):|You have an error in your SQL syntax(?: near
'|;)|cannot take a \w+ data type as an argument\*.|incorrect syntax near (?:\'|the\
b|@@error\b)|microsoft jet database engine error '8|ORA-\d{5}: )|\[Microsoft\]\
[ODBC )" \
"phase:4,t:none,ctl:auditLogParts=+E,deny,log,auditlog,status:500,msg:'SQL
Information Leakage',id:'970003',tag:'LEAKAGE/ERRORS',severity:'4'"
|
If
the message in the response successfully matches against the regular
expression (indicating that an SQL error has occurred), ModSecurity
sends a 501 status code. This is non-standard behavior, but it is used
to confuse automated clients and scanners.
This type of
response analysis and error suppression does not eliminate the SQL
injection vulnerability or help in the case of blind SQL injection, but
it is still an important defense-in-depth security mechanism.
Intrusion Detection Capabilities
Lastly, WAFs should be
able to monitor application behavior passively, take action in the event
of suspicious behavior, and maintain a non-reputable log of events for a
forensic analysis following an SQL injection incident. The logs should
give you the information to determine whether your application was
attacked and provide enough information for reproducing the attack
string. Blocking and rejecting malicious input aside, the ability to add
intrusion detection features to your application without changing a
line of code is a strong argument for the use of WAFs. When performing a
forensic analysis following an SQL injection incident, nothing is more
frustrating than having to rely on Web server log files, which often
contain only a small subset of the data sent in the request.
In
summary, with ModSecurity it is possible to stop SQL injection attacks,
patch a known SQL injection vulnerability, detect attack attempts, and
suppress SQL error messages that often facilitate exploitation of SQL
injection vulnerabilities. Now that we’ve discussed ModSecurity
and WAFs in general, we’re going to look at some solutions that could
be considered a WAF but are not as robust. However, they can be just as
effective depending on the scenario, and they can be potentially cheaper
in cost and resource requirements to deploy.