1 <?xml version="1.0" encoding="UTF-8"?>
3 <title>ModSecurity Migration Matrix</title>
6 <releaseinfo>Version 1.0 / (April 10, 2007)</releaseinfo>
11 <holder>Breach Security, Inc. (<ulink
12 url="http://www.breach.com">http://www.breach.com</ulink>)</holder>
16 <section id="01-introduction">
17 <title>Migration from 1.x to 2.x</title>
20 <para>If you are already using an older version of ModSecurity and want
21 to upgrade/migrate your existing custom rules, you will need to ensure
22 that you properly translate all of your Directives to their
23 corresponding 2.0 counterparts. Some directives have simply changed
24 names, however some directives actually behave differently so it is
25 important that you also review the entire 2.0 Reference Manual. The
26 migration matrix show below should help you to translate ModSecurity 1.X
27 directives to the 2.0 values. There are also some notes that provide
28 additional information is a directive significantly changed how it
34 <emphasis role="bold">Feature/Capability</emphasis>
38 <emphasis role="bold">ModSecurity 1.x</emphasis>
42 <emphasis role="bold">ModSecurity 2.x</emphasis>
46 <emphasis role="bold">Notes</emphasis>
50 <emphasis role="bold">How To Upgrade</emphasis>
56 <emphasis role="bold">Apache Version Supported</emphasis>
59 <td>Apache 1.x/2.x</td>
61 <td>Apache 2.x Only</td>
63 <td>ModSecurity 2.0 will only work with Apache 2.x and not the older
66 <td>If you are mainly an Apache 1.3 shop and/or you have other web
67 servers that you want to protect (such as IIS) an alternative
68 solution is to deploy an Apache 2.x reverse proxy server and
69 implement ModSecurity 2.x on it.</td>
74 <emphasis role="bold">Installation</emphasis>
77 <td>Can be installed as either a DSO module or as a statically
80 <td>Can currently only be installed as a DSO module.</td>
82 <td>In 1.x, you could use apxs directly, while in 2.x you must use
83 the provided Makefile.</td>
85 <td>If you can not use DSOs in your current Apache configs, you may
86 look at implementing a front-end Apache reverse proxy server.</td>
91 <emphasis role="bold">Configuration - IfModule</emphasis>
94 <td>Apache 1.x - <IfModule mod_security.c> Apache 2.x -
95 <IfModule security_module></td>
97 <td><IfModule security2_module></td>
99 <td>The syntax of using IfModule has changed between Apache 1.x and
102 <td>Make sure that any existing <IfModule> directives uses the
108 <emphasis role="bold">Processing Phases Supported</emphasis>
115 <td>ModSecurity 1.x supports:<itemizedlist>
117 <para>Inbound - which corresponds to current Mod 2.x Request
118 Body phase and the Apache “fixups” phase.</para>
122 <para>Outbound - which corresponds to current Mod 2.x Response
123 Body phase and just after the Apache “response” processing
126 </itemizedlist>ModSecurity 2.x supports: <itemizedlist>
128 <para>Request Headers – which corresponds with the Apache
129 “post-read-request” phase.</para>
133 <para>Request Body – which corresponds with the Apache
134 “fixups” phase.</para>
138 <para>Response Headers – which corresponds to the Apache
139 “response” phase.</para>
143 <para>Response Body – which corresponds to just after the
144 Apache “response” phase.</para>
148 <para>Logging - which is the Apache logging phase.</para>
152 <td>If you are translating existing 1.x rules
153 (SecFilter/SecFilterSelective) then you should use phase:2 in the
154 new rule syntax. Translate existing OUTPUT rules to run in
160 <emphasis role="bold">Directive to turn On/Off the Rule
164 <td>SecFilterEngine</td>
166 <td>SecRuleEngine ctl:ruleEngine=</td>
171 <para>1.x – values were On, Off and DynamicOnly and was a
172 Global directive.</para>
176 <para>2.x - values are On, Off or DetectionOnly.</para>
180 <para>2.x – the “ctl” action can control the RuleEngine
181 dynamically for individual requests.</para>
188 <td>Replace SecFilterEngine with SecRuleEngine. The DynamicOnly mode
189 is not supported in ModSecurity 2.x because it was sometimes
190 difficult for ModSecurity to determine if a particular request was
191 dynamic in nature or not. Use of AddType vs. AddHandler would cause
192 problems. Since this logic relies on the internal (and not entirely
193 documented) workings of Apache and on the chosen configuration it
194 also makes it somewhat unpredictable.</td>
199 <emphasis role="bold">Directive to handle the Audit
203 <td>SecAuditEngine On, Off, RelevantOnly, DynamicOrRelevant</td>
205 <td>SecAuditEngine On, Off, RelevantOnly</td>
207 <td>In 2.x, the DynamicOrRelevant option was discontinued.</td>
209 <td>If you are using DynamicOrRelevant then switch it to
215 <emphasis role="bold">Default Rule Action</emphasis>
218 <td>SecFilterDefaultAction</td>
220 <td>SecDefaultAction</td>
225 <para>1.x – SecFilterDefaultAction could be used anywhere in
226 the config and it would be picked up by all rules.</para>
230 <para>2.x – SecDefaultAction must come before rules and be
231 specified in each context. The default setting for this
232 directive (if it is not specified otherwise) is –
233 <literal>SecDefaultAction
234 phase:2,log,deny,status:403,\</literal></para>
237 <literal>t:lowercase,t:replaceNulls,\</literal>
241 <literal>t:compressWhitespace</literal>
249 <td>Replace SecFilterDefaultAction with SecDefaultAction.
250 Optionally, you can group rules together where you would like to use
251 the same action and then specify a SecDefaultAction line before each
252 group. Also keep in mind that while most actions specified on
253 individual rules will supersede those specified in SecDefaultAction,
254 transformation functions are additive. So, if you specify a
255 “t:base64Decode” transformation function to a rule, it will be added
256 after the lowercase, replaceNulls and compressWhitespace
257 transformation functions.</td>
262 <emphasis role="bold">Debug Logging</emphasis>
265 <td>SecFilterDebugLog SecFilterDebugLogLevel</td>
267 <td>SecDebugLog SecDebugLogLevel</td>
269 <td>Name change only.</td>
271 <td>Change the names of these directives to their 2.x
277 <emphasis role="bold">Rule Directive(s)</emphasis>
280 <td>SecFilter SecFilterSelective</td>
287 <para>In Mod 1.x, SecFilter and SecFilterSelective were case
292 <para>In Mod 2.x, the case of data is not altered unless the
293 lowercase transformation funce is used. SecRule has
294 essentially the same rule syntax as SecFilterSelective.</para>
299 <td>Replace SecFilterSelective with SecRule and make sure to
300 translate the variable tested according to this list. Replace any
301 SecFilter with a new SecRule directive. You will need to specify a
302 new Variable location and a phase. You can optionally specify a
303 disruptive action, otherwise it will be inherited from a previous
304 SecDefaultAction. </td>
309 <emphasis role="bold">Rule Exceptions</emphasis>
312 <td>Whitelist approach – use pass, allow actions False Positive
313 Approach – use SecFilterRemove</td>
315 <td>Whitelist approach – use pass, allow and ctl actions. False
316 Positive Approach – use SecRuleRemoveById and Apache Scope
319 <td>In Mod 2.x, using the “allow” action may not be enough to truly
320 let a request through as “allow” only applies to the current
321 processing phase. This means that rules in subsequent phases may act
322 on the request. This is why you need to also use the
323 “ctl:ruleEngine=Off” action if you really want to let a request
326 <td>See Blog post on handling false positives and creating custom
328 http://www.modsecurity.org/blog/archives/2007/02/handling_false.html</td>
333 <emphasis role="bold">Directive to control rule inheritance to
334 Apache Scope locations (Virtual Hosts, Location,
335 Directory)</emphasis>
338 <td>SecFilterInheritance</td>
340 <td>SecRuleInheritance</td>
342 <td>The best use of this directive is when you want to start with a
343 “clean slate” so you can use SecRuleInheritance Off and then specify
344 your new rule sets. Note – Rule Inheritance does not work across
345 Apache Scope directives (such as Vhosts, Location and Directory
346 directives). This means that you can not use SecRuleInheritance On
347 to inherit a SecDefaultAction directive within these new contexts.
348 This is an issue with the way that Apache inherits contexts. It is
349 for this reason that we recommend that you specify new
350 SecDefaultAction directives within each Apache scope location that
353 <td>Translate any existing “SecFilterInheritance Off” rules directly
354 to “SecRuleInheritance Off”. Then replace any “SecFilterInheritance
355 On” directives inside Apache Scope context locations with a new
356 SecDefaultAction directive and then import the rules that you want
357 with standard Apache Include directives.</td>
362 <emphasis role="bold">Ability to manage rules in Apache Scope
366 <td>SecFilterImport SecFilterRemove</td>
368 <td>SecRuleRemoveById SecRuleRemoveByMsg</td>
370 <td>SecFilterRemove is now SecRuleRemoveById or SecRuleRemoveByMsg.
371 SecFilterImport is no longer supported.</td>
373 <td>Change all of your existing SecFilterRemove rules to
374 SecRuleRemoveById. For any existing SecFilterImport rules, you will
375 need to either copy the rule into the context or use an Apache
376 Include Directive to include entire files (such as including the
377 Core Rules files).</td>
382 <emphasis role="bold">Ability to verify URL/UTF8
386 <td>SecFilterCheckURLEncoding SecFilterCheckUnicodeEncoding </td>
388 <td>@validateUrlEncoding @validateUtf8Encoding </td>
390 <td>In Mod 1.x, these were Global Directives and in Mod 2.x they are
391 Operators that can be applied selectively to each rule.</td>
393 <td>Add the rules that will do exactly the same as the
399 <emphasis role="bold">Ability to enforce a Byte Range (allowed
400 character set)</emphasis>
403 <td>SecFilterForceByteRange</td>
405 <td>@validateByteRange</td>
407 <td>In Mod 1.x, this was a Global Directive and in Mod 2.x it is an
408 Operator that can be applied selectively to each rule. In Mod 1.x,
409 this directive did not check POST payloads when multipart/form-data
410 encoding was used.</td>
412 <td>You can now add @validateByteRange operators to individual
413 rules. This helps if you have differences in allowed character sets
414 for different portions of the web application.</td>
419 <emphasis role="bold">Ability to Normalize/Transform Request
423 <td>ModSecurity 1.x automatically applied the following
424 transformations:<itemizedlist>
426 <para>On Windows only, convert \ to /</para>
430 <para>Reduce /./ to /</para>
434 <para>Reduce // to /</para>
438 <para>Decode URL-encoded characters</para>
442 <para>Converts Null Bytes to Space character</para>
449 <para>base64Decode </para>
453 <para>base64Encode</para>
457 <para>compressWhitespace</para>
461 <para>escapeSeqDecode</para>
465 <para>hexDecode</para>
469 <para>hexEncode</para>
473 <para>htmlEntityDecode</para>
477 <para>lowercase</para>
489 <para>normalisePath</para>
493 <para>normalisePathWin</para>
497 <para>removeNulls</para>
501 <para>removeWhitespace</para>
505 <para>replaceComments</para>
509 <para>replaceNulls</para>
513 <para>urlDecode</para>
517 <para>urlDecodeUni</para>
521 <para>urlEncode</para>
532 <td>In Mod 1.x, the normalization functions were implicit and you
533 could not control them. In Mod 2.x, not normalization is done by
534 default. There are now “Transformation Functions” that allow you to
535 selectively apply normalizations and other features.</td>
537 <td>You should add the appropriate transformation functions to
538 either SecDefaultAction directive or each individual rule. See the
539 Core Rules files for examples. Keep in mind that transformation
540 functions are inherited from parent SecDefaultAction directives.
541 Care should be taken to ensure that RegEx patterns match the data
542 after transformation functions are applied. In order to avoid
543 possible unwanted inherited transformation functions, use “t:none”
544 to either not apply any transformation functions or you can then
545 specify specific transformation functions after “t:none”.</td>
550 <emphasis role="bold">Ability to specify an arbitrary Request
551 Header in a rule</emphasis>
554 <td>HEADER_headername HTTP_headername</td>
556 <td>REQUEST_HEADERS REQUEST_HEADERS:headername
557 REQUEST_HEADERS:/RegEx/</td>
559 <td>The HTTP_headername syntax has been superseded by the new
560 REQUEST_HEADERS:headername syntax and will not be supported in
561 future releases. The advantage to using the new syntax is that you
562 can also use RegEx in the headername portion.</td>
564 <td>Translate any existing HTTP_headername directives to
565 REQUEST_HEADERS:headername. Also consider consolidating header
566 checks by using Regular Expressions in the header name portion of
572 <emphasis role="bold">Variable/Location for the entire URL Request
578 <td>REQUEST_LINE</td>
580 <td>Functions the same. The variable includes the Request Method,
581 URI and HTTP version data.</td>
583 <td>Translate any existing THE_REQUEST directives to REQUEST_LINE
589 <emphasis role="bold">Variable/Location for Arguments</emphasis>
594 <td>ARGS:name ARGS:/RegEx/</td>
596 <td>Similar to the HTTP_headername situation, the advantage of the
597 new syntax is the ability to use RegEx in the argument name.</td>
599 <td>Translate any existing ARG_name directives to ARGS:name
605 <emphasis role="bold">Accessing Request Bodies</emphasis>
608 <td>SecFilterScanPOST POST_PAYLOAD</td>
610 <td>SecRequestBodyAccess Phase:2 REQUEST_BODY</td>
612 <td>In 2.x, the directive is now called SecRequestBodyAccess and it
613 is more flexible than SecFilterScanPOST as it is able to inspect all
614 request bodies (such as PUT and XML, etc…) and not just POST
617 <td>Replace the existing SecFilterScanPOST directive with
618 SecRequestBodyAccess. For individual rules where you want to inspect
619 the request bodies, you must specify REQUEST_BODY as the variable
620 and you also must ensure that it is running in phase:2 (by either an
621 inherited SecDefaultAction setting or by explicitly specifying the
622 phase within the rule action).</td>
627 <emphasis role="bold">Ability to disable POST/Request buffering
628 dynamically</emphasis>
631 <td>MODSEC_NOPOSTBUFFERING</td>
633 <td>ctl:requestBodyAccess=Off</td>
635 <td>In 2.x, you can use the ctl action to turn on/off request body
636 access on a per rule basis.</td>
638 <td>Take any existing entries in the httpd.conf file that set the
639 MODSEC_NOPOSTBUFFERING Env variable and translate them to Mod 2.x
645 <emphasis role="bold">Accessing Cookies</emphasis>
648 <td>COOKIES COOKIES_COUNT COOKIES_NAMES COOKIES_VALUES
651 <td>REQUEST_HEADERS:Cookie REQUEST_COOKIES_NAMES
652 REQUEST_COOKIES_NAMES:name REQUEST_COOKIES_NAMES:/RegEx/
653 REQUEST_COOKIES REQUEST_COOKIES:name REQUEST_COOKIES:/RegEx/</td>
655 <td> In 2.x, you can use the “&” character to “count” the number
656 of variables. While there are different ways to access request
657 cookies, the main difference between them are that
658 REQUEST_HEADERS:Cookie will include all of the “raw” Cookie data
659 while any of the REQUEST_COOKIES variable values are parsed.</td>
661 <td>Translate rules as follows – Mod 1.x -> Mod 2.x COOKIES ->
662 REQUEST_COOKIES COOKIES_COUNT -> &REQUEST_COOKIES
663 COOKIES_NAMES -> REQUEST_COOKIES_NAMES COOKIES_VALUES ->
664 REQUEST_COOKIES COOKIE_name -> REQUEST_COOKIES:name</td>
669 <emphasis role="bold">Counting Variables</emphasis>
672 <td>ARGS_COUNT COOKIES_COUNT HEADERS_COUNT FILES_COUNT</td>
674 <td>&ARGS &REQUEST_COOKIES &REQUEST_HEADERS
677 <td>In 2.x, prepending the “&” character will count the number
678 of variables. Example – 1.x – HEADERS_COUNT 2.x -
679 &REQUEST_HEADERS</td>
681 <td>Translate existing 1.x rules as listed.</td>
686 <emphasis role="bold">Accessing HTTP Status Code</emphasis>
689 <td>OUTPUT_STATUS</td>
691 <td>RESPONSE_STATUS Phase:3</td>
693 <td>In 2.x, you need to specify both the RESPONSE_STATUS variable
694 and phase:3 with the rule.</td>
696 <td>Translate any existing 1.x OUTPUT STATUS rules to use
697 RESPONSE_STATUS and phase:3.</td>
702 <emphasis role="bold">Accessing Response Bodies/Post
706 <td>SecFilterScanOutput SecFilterOutputMimeTypes OUTPUT</td>
708 <td>SecResponseBodyAccess SecResponseBodyMimeTypes RESPONSE_BODY
711 <td>In 1.x, neither skipnext nor chain could be used on the OUTPUT
712 location. In 2.x, both actions can be used on RESPONSE_BODY</td>
714 <td>Translate directives/rules as follows – Mod 1.x -> Mod 2.x
715 SecFilterScanOutput -> SecResponseBodyAccess
716 SecFilterOutputMimeTypes -> SecResponseBodyMimeTypes OUTPUT ->
717 RESPONSE_BODY/Phase:4</td>
722 <emphasis role="bold">Cookie Normalization</emphasis>
725 <td>SecFilterCookieFormat SecFilterNormalizeCookies</td>
727 <td>SecCookieFormat</td>
729 <td>SecFilterNormalizeCookies is no longer supported as Mod 2.x
730 transformation functions can now be used to normalize all Variables
731 including Cookie data.</td>
733 <td>Change SecFilterCookieFormat to SecCookieFormat. When specifying
734 Cookie variables, then apply the applicable transformation functions
735 in the action field of the rule.</td>
740 <emphasis role="bold">Ability to skip rules</emphasis>
747 <td>In Mod 2.x – skip takes into account chained rulesets and treats
748 them as 1 rule. In Mod 1.x – skipnext treated each rule directive as
749 an individual rule regardless of whether or not they were tied
750 together as a chained ruleset.</td>
752 <td>Translate all skipnext rules to skip, however make sure to
753 factor in any chained rulesets that may follow and adjust the skip
754 number accordingly.</td>
759 <emphasis role="bold">Adding/Removing Audit Log Data on a per rule
765 <td>clt:auditLogParts=</td>
767 <td>The rules function the same.</td>
769 <td>Translate any existing logparts actions to the ctl:auditLogParts
775 <emphasis role="bold">Inspecting uploaded files</emphasis>
778 <td>SecUploadApproveScript</td>
780 <td>@inspectFile FILES_TMPNAMES</td>
782 <td>The main difference here is that now @inspectFile is an Operator
783 vs. a global Directive. This means that you can apply @inspectFile
784 to individual rules and use different scripts as appropriate. Also,
785 the return codes are now reversed – In 1.x, a return code of “1”
786 means that the file would be allowed. In 2.x, a return code of “1”
787 means that the file would be denied. </td>
789 <td>In order to scan/inspect uploaded files in 2.x, you need to
790 create specific rules that use the FILES_TMPNAMES variable (as these
791 are the names of the files that are temporarily stored on disk) and
792 then use the @inspectFile Operator on each rule. Also, make sure to
793 swap your return codes in existing scripts as mentioned in the notes
799 <emphasis role="bold">Memory limits for uploaded files</emphasis>
802 <td>SecUploadInMemoryLimit</td>
804 <td>SecRequestBodyInMemoryLimit</td>
806 <td>These two directives function the same.</td>
808 <td>Change the SecUploadInMemoryLimit directive to
809 SecRequestBodyInMemoryLimit.</td>