diff --git a/CHANGES b/CHANGES index b899efaadc..b293d1067e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,16 +1,31 @@ 01 Nov 2012 - 2.7.1 ------------------- + * Changed "Encryption" name of directives and options related to hmac feature to "Hash". + + SecEncryptionEngine to SecHashEngine + SecEncryptionKey to SecHashKey + SecEncryptionParam to SecHashParam + SecEncryptionMethodRx to SecHashMethodRx + SecEncryptionMethodPm to SecHashMethodPm + @validateEncryption to @validateHash + ctl:EncryptionEnforcement to ctl:HashEnforcement + ctl:EncryptionEngine to ctl:HashEngine + * Added a better random bytes generator using apr_generate_random_bytes() to create the HMAC key. + * Fixed byte conversion issue during logging under Linux s390x platform. + * Fixed compilation bug with LibXML2 2.9.0 (Thanks Athmane Madjoudj). * Fixed parsing error with modsecurity-recommended.conf and Apache 2.4. - * Fixed DROP action was disabled for Apache 2 module. + * Fixed DROP action was disabled for Apache 2 module by mistake. - * Updated Reference Manual. + * Fixed bug when use ctl:ruleRemoveByTag. + + * The doc/ directory now contains the instructions to access online documentation. 15 Oct 2012 - 2.7.0 ------------------- diff --git a/README.TXT b/README.TXT index 907c8034d7..ff2a0beef3 100644 --- a/README.TXT +++ b/README.TXT @@ -28,8 +28,7 @@ oject Download: -https://sourceforge.net/projects/mod-security/files/modsecurity-crs/0-CURRE -NT/ +https://github.com/SpiderLabs/owasp-modsecurity-crs ---------------------------------- diff --git a/apache2/Makefile.am b/apache2/Makefile.am index 1d233162c8..f79f50772d 100644 --- a/apache2/Makefile.am +++ b/apache2/Makefile.am @@ -43,7 +43,7 @@ mod_security2_la_LDFLAGS = -module -avoid-version \ endif if LINUX -mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \ +mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version -R @PCRE_LD_PATH@ \ @APR_LDFLAGS@ @APU_LDFLAGS@ @APXS_LDFLAGS@ \ @PCRE_LDFLAGS@ @LIBXML2_LDFLAGS@ @LUA_LDFLAGS@ endif @@ -71,5 +71,5 @@ install-exec-hook: $(pkglib_LTLIBRARIES) for m in $(pkglib_LTLIBRARIES); do \ base=`echo $$m | sed 's/\..*//'`; \ rm -f $(DESTDIR)$(pkglibdir)/$$base.*a; \ - cp -p $(DESTDIR)$(pkglibdir)/$$base.so $(APXS_MODULES); \ + install -D -m444 $(DESTDIR)$(pkglibdir)/$$base.so $(DESTDIR)$(APXS_MODULES); \ done diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 45f1587fd4..830070a81e 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -67,7 +67,7 @@ void *create_directory_config(apr_pool_t *mp, char *path) dcfg->rule_inheritance = NOT_SET; dcfg->rule_exceptions = apr_array_make(mp, 16, sizeof(rule_exception *)); - dcfg->encryption_method = apr_array_make(mp, 16, sizeof(encryption_method *)); + dcfg->hash_method = apr_array_make(mp, 16, sizeof(hash_method *)); /* audit log variables */ dcfg->auditlog_flag = NOT_SET; @@ -139,8 +139,8 @@ void *create_directory_config(apr_pool_t *mp, char *path) dcfg->crypto_key_len = NOT_SET; dcfg->crypto_key_add = NOT_SET; dcfg->crypto_param_name = NOT_SET_P; - dcfg->encryption_is_enabled = NOT_SET; - dcfg->encryption_enforcement = NOT_SET; + dcfg->hash_is_enabled = NOT_SET; + dcfg->hash_enforcement = NOT_SET; dcfg->crypto_hash_href_rx = NOT_SET; dcfg->crypto_hash_faction_rx = NOT_SET; dcfg->crypto_hash_location_rx = NOT_SET; @@ -446,8 +446,8 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) merged->rule_exceptions = apr_array_append(mp, parent->rule_exceptions, child->rule_exceptions); - merged->encryption_method = apr_array_append(mp, parent->encryption_method, - child->encryption_method); + merged->hash_method = apr_array_append(mp, parent->hash_method, + child->hash_method); /* audit log variables */ merged->auditlog_flag = (child->auditlog_flag == NOT_SET @@ -552,7 +552,7 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) merged->col_timeout = (child->col_timeout == NOT_SET ? parent->col_timeout : child->col_timeout); - /* Encryption */ + /* Hash */ merged->crypto_key = (child->crypto_key == NOT_SET_P ? parent->crypto_key : child->crypto_key); merged->crypto_key_len = (child->crypto_key_len == NOT_SET @@ -561,10 +561,10 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) ? parent->crypto_key_add : child->crypto_key_add); merged->crypto_param_name = (child->crypto_param_name == NOT_SET_P ? parent->crypto_param_name : child->crypto_param_name); - merged->encryption_is_enabled = (child->encryption_is_enabled == NOT_SET - ? parent->encryption_is_enabled : child->encryption_is_enabled); - merged->encryption_enforcement = (child->encryption_enforcement == NOT_SET - ? parent->encryption_enforcement : child->encryption_enforcement); + merged->hash_is_enabled = (child->hash_is_enabled == NOT_SET + ? parent->hash_is_enabled : child->hash_is_enabled); + merged->hash_enforcement = (child->hash_enforcement == NOT_SET + ? parent->hash_enforcement : child->hash_enforcement); merged->crypto_hash_href_rx = (child->crypto_hash_href_rx == NOT_SET ? parent->crypto_hash_href_rx : child->crypto_hash_href_rx); merged->crypto_hash_faction_rx = (child->crypto_hash_faction_rx == NOT_SET @@ -687,13 +687,13 @@ void init_directory_config(directory_config *dcfg) if (dcfg->col_timeout == NOT_SET) dcfg->col_timeout = 3600; - /* Encryption */ + /* Hash */ if (dcfg->crypto_key == NOT_SET_P) dcfg->crypto_key = getkey(dcfg->mp); if (dcfg->crypto_key_len == NOT_SET) dcfg->crypto_key_len = strlen(dcfg->crypto_key); - if (dcfg->crypto_key_add == NOT_SET) dcfg->crypto_key_add = ENCRYPTION_KEYONLY; + if (dcfg->crypto_key_add == NOT_SET) dcfg->crypto_key_add = HASH_KEYONLY; if (dcfg->crypto_param_name == NOT_SET_P) dcfg->crypto_param_name = "crypt"; - if (dcfg->encryption_is_enabled == NOT_SET) dcfg->encryption_is_enabled = ENCRYPTION_DISABLED; - if (dcfg->encryption_enforcement == NOT_SET) dcfg->encryption_enforcement = ENCRYPTION_DISABLED; + if (dcfg->hash_is_enabled == NOT_SET) dcfg->hash_is_enabled = HASH_DISABLED; + if (dcfg->hash_enforcement == NOT_SET) dcfg->hash_enforcement = HASH_DISABLED; if (dcfg->crypto_hash_href_rx == NOT_SET) dcfg->crypto_hash_href_rx = 0; if (dcfg->crypto_hash_faction_rx == NOT_SET) dcfg->crypto_hash_faction_rx = 0; if (dcfg->crypto_hash_location_rx == NOT_SET) dcfg->crypto_hash_location_rx = 0; @@ -2255,7 +2255,7 @@ static const char *cmd_sensor_id(cmd_parms *cmd, void *_dcfg, const char *p1) /** -* \brief Add SecEncryption configuration option +* \brief Add SecHash configuration option * * \param cmd Pointer to configuration data * \param _dcfg Pointer to directory configuration @@ -2264,18 +2264,18 @@ static const char *cmd_sensor_id(cmd_parms *cmd, void *_dcfg, const char *p1) * \retval NULL On failure * \retval apr_psprintf On Success */ -static const char *cmd_encryption_engine(cmd_parms *cmd, void *_dcfg, const char *p1) +static const char *cmd_hash_engine(cmd_parms *cmd, void *_dcfg, const char *p1) { directory_config *dcfg = (directory_config *)_dcfg; if (dcfg == NULL) return NULL; if (strcasecmp(p1, "on") == 0) { - dcfg->encryption_is_enabled = ENCRYPTION_ENABLED; - dcfg->encryption_enforcement = ENCRYPTION_ENABLED; + dcfg->hash_is_enabled = HASH_ENABLED; + dcfg->hash_enforcement = HASH_ENABLED; } else if (strcasecmp(p1, "off") == 0) { - dcfg->encryption_is_enabled = ENCRYPTION_DISABLED; - dcfg->encryption_enforcement = ENCRYPTION_DISABLED; + dcfg->hash_is_enabled = HASH_DISABLED; + dcfg->hash_enforcement = HASH_DISABLED; } else return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRuleEngine: %s", p1); @@ -2283,7 +2283,7 @@ static const char *cmd_encryption_engine(cmd_parms *cmd, void *_dcfg, const char } /** -* \brief Add SecEncryptionPram configuration option +* \brief Add SecHashPram configuration option * * \param cmd Pointer to configuration data * \param _dcfg Pointer to directory configuration @@ -2291,7 +2291,7 @@ static const char *cmd_encryption_engine(cmd_parms *cmd, void *_dcfg, const char * * \retval NULL On success */ -static const char *cmd_encryption_param(cmd_parms *cmd, void *_dcfg, const char *p1) +static const char *cmd_hash_param(cmd_parms *cmd, void *_dcfg, const char *p1) { directory_config *dcfg = (directory_config *)_dcfg; @@ -2304,7 +2304,7 @@ static const char *cmd_encryption_param(cmd_parms *cmd, void *_dcfg, const char } /** -* \brief Add SecEncryptionKey configuration option +* \brief Add SecHashKey configuration option * * \param cmd Pointer to configuration data * \param _dcfg Pointer to directory configuration @@ -2313,7 +2313,7 @@ static const char *cmd_encryption_param(cmd_parms *cmd, void *_dcfg, const char * * \retval NULL On success */ -static const char *cmd_encryption_key(cmd_parms *cmd, void *_dcfg, const char *_p1, const char *_p2) +static const char *cmd_hash_key(cmd_parms *cmd, void *_dcfg, const char *_p1, const char *_p2) { directory_config *dcfg = (directory_config *)_dcfg; char *p1 = NULL; @@ -2335,17 +2335,17 @@ static const char *cmd_encryption_key(cmd_parms *cmd, void *_dcfg, const char *_ return NULL; } else { if (strcasecmp(_p2, "KeyOnly") == 0) - dcfg->crypto_key_add = ENCRYPTION_KEYONLY; + dcfg->crypto_key_add = HASH_KEYONLY; else if (strcasecmp(_p2, "SessionID") == 0) - dcfg->crypto_key_add = ENCRYPTION_SESSIONID; + dcfg->crypto_key_add = HASH_SESSIONID; else if (strcasecmp(_p2, "RemoteIP") == 0) - dcfg->crypto_key_add = ENCRYPTION_REMOTEIP; + dcfg->crypto_key_add = HASH_REMOTEIP; } return NULL; } /** -* \brief Add SecEncryptionMethodPm configuration option +* \brief Add SecHashMethodPm configuration option * * \param cmd Pointer to configuration data * \param _dcfg Pointer to directory configuration @@ -2355,11 +2355,11 @@ static const char *cmd_encryption_key(cmd_parms *cmd, void *_dcfg, const char *_ * \retval NULL On failure * \retval apr_psprintf On Success */ -static const char *cmd_encryption_method_pm(cmd_parms *cmd, void *_dcfg, +static const char *cmd_hash_method_pm(cmd_parms *cmd, void *_dcfg, const char *p1, const char *p2) { directory_config *dcfg = (directory_config *)_dcfg; - rule_exception *re = apr_pcalloc(cmd->pool, sizeof(encryption_method)); + rule_exception *re = apr_pcalloc(cmd->pool, sizeof(hash_method)); const char *_p2 = apr_pstrdup(cmd->pool, p2); ACMP *p = NULL; const char *phrase = NULL; @@ -2385,7 +2385,7 @@ static const char *cmd_encryption_method_pm(cmd_parms *cmd, void *_dcfg, acmp_prepare(p); if (strcasecmp(p1, "HashHref") == 0) { - re->type = ENCRYPTION_URL_HREF_HASH_PM; + re->type = HASH_URL_HREF_HASH_PM; re->param = _p2; re->param_data = (void *)p; if (re->param_data == NULL) { @@ -2394,7 +2394,7 @@ static const char *cmd_encryption_method_pm(cmd_parms *cmd, void *_dcfg, dcfg->crypto_hash_href_pm = 1; } else if (strcasecmp(p1, "HashFormAction") == 0) { - re->type = ENCRYPTION_URL_FACTION_HASH_PM; + re->type = HASH_URL_FACTION_HASH_PM; re->param = _p2; re->param_data = (void *)p; if (re->param_data == NULL) { @@ -2403,7 +2403,7 @@ static const char *cmd_encryption_method_pm(cmd_parms *cmd, void *_dcfg, dcfg->crypto_hash_faction_pm = 1; } else if (strcasecmp(p1, "HashLocation") == 0) { - re->type = ENCRYPTION_URL_LOCATION_HASH_PM; + re->type = HASH_URL_LOCATION_HASH_PM; re->param = _p2; re->param_data = (void *)p; if (re->param_data == NULL) { @@ -2412,7 +2412,7 @@ static const char *cmd_encryption_method_pm(cmd_parms *cmd, void *_dcfg, dcfg->crypto_hash_location_pm = 1; } else if (strcasecmp(p1, "HashIframeSrc") == 0) { - re->type = ENCRYPTION_URL_IFRAMESRC_HASH_PM; + re->type = HASH_URL_IFRAMESRC_HASH_PM; re->param = _p2; re->param_data = (void *)p; if (re->param_data == NULL) { @@ -2421,7 +2421,7 @@ static const char *cmd_encryption_method_pm(cmd_parms *cmd, void *_dcfg, dcfg->crypto_hash_iframesrc_pm = 1; } else if (strcasecmp(p1, "HashFrameSrc") == 0) { - re->type = ENCRYPTION_URL_FRAMESRC_HASH_PM; + re->type = HASH_URL_FRAMESRC_HASH_PM; re->param = _p2; re->param_data = (void *)p; if (re->param_data == NULL) { @@ -2430,13 +2430,13 @@ static const char *cmd_encryption_method_pm(cmd_parms *cmd, void *_dcfg, dcfg->crypto_hash_framesrc_pm = 1; } - *(encryption_method **)apr_array_push(dcfg->encryption_method) = re; + *(hash_method **)apr_array_push(dcfg->hash_method) = re; return NULL; } /** - * \brief Add SecEncryptionMethodRx configuration option + * \brief Add SecHashMethodRx configuration option * * \param cmd Pointer to configuration data * \param _dcfg Pointer to directory configuration @@ -2446,16 +2446,16 @@ static const char *cmd_encryption_method_pm(cmd_parms *cmd, void *_dcfg, * \retval NULL On failure * \retval apr_psprintf On Success */ -static const char *cmd_encryption_method_rx(cmd_parms *cmd, void *_dcfg, +static const char *cmd_hash_method_rx(cmd_parms *cmd, void *_dcfg, const char *p1, const char *p2) { directory_config *dcfg = (directory_config *)_dcfg; - rule_exception *re = apr_pcalloc(cmd->pool, sizeof(encryption_method)); + rule_exception *re = apr_pcalloc(cmd->pool, sizeof(hash_method)); const char *_p2 = apr_pstrdup(cmd->pool, p2); if (dcfg == NULL) return NULL; if (strcasecmp(p1, "HashHref") == 0) { - re->type = ENCRYPTION_URL_HREF_HASH_RX; + re->type = HASH_URL_HREF_HASH_RX; re->param = _p2; re->param_data = msc_pregcomp(cmd->pool, p2, 0, NULL, NULL); if (re->param_data == NULL) { @@ -2464,7 +2464,7 @@ static const char *cmd_encryption_method_rx(cmd_parms *cmd, void *_dcfg, dcfg->crypto_hash_href_rx = 1; } else if (strcasecmp(p1, "HashFormAction") == 0) { - re->type = ENCRYPTION_URL_FACTION_HASH_RX; + re->type = HASH_URL_FACTION_HASH_RX; re->param = _p2; re->param_data = msc_pregcomp(cmd->pool, p2, 0, NULL, NULL); if (re->param_data == NULL) { @@ -2473,7 +2473,7 @@ static const char *cmd_encryption_method_rx(cmd_parms *cmd, void *_dcfg, dcfg->crypto_hash_faction_rx = 1; } else if (strcasecmp(p1, "HashLocation") == 0) { - re->type = ENCRYPTION_URL_LOCATION_HASH_RX; + re->type = HASH_URL_LOCATION_HASH_RX; re->param = _p2; re->param_data = msc_pregcomp(cmd->pool, p2, 0, NULL, NULL); if (re->param_data == NULL) { @@ -2482,7 +2482,7 @@ static const char *cmd_encryption_method_rx(cmd_parms *cmd, void *_dcfg, dcfg->crypto_hash_location_rx = 1; } else if (strcasecmp(p1, "HashIframeSrc") == 0) { - re->type = ENCRYPTION_URL_IFRAMESRC_HASH_RX; + re->type = HASH_URL_IFRAMESRC_HASH_RX; re->param = _p2; re->param_data = msc_pregcomp(cmd->pool, p2, 0, NULL, NULL); if (re->param_data == NULL) { @@ -2491,7 +2491,7 @@ static const char *cmd_encryption_method_rx(cmd_parms *cmd, void *_dcfg, dcfg->crypto_hash_iframesrc_rx = 1; } else if (strcasecmp(p1, "HashFrameSrc") == 0) { - re->type = ENCRYPTION_URL_FRAMESRC_HASH_RX; + re->type = HASH_URL_FRAMESRC_HASH_RX; re->param = _p2; re->param_data = msc_pregcomp(cmd->pool, p2, 0, NULL, NULL); if (re->param_data == NULL) { @@ -2500,7 +2500,7 @@ static const char *cmd_encryption_method_rx(cmd_parms *cmd, void *_dcfg, dcfg->crypto_hash_framesrc_rx = 1; } - *(encryption_method **)apr_array_push(dcfg->encryption_method) = re; + *(hash_method **)apr_array_push(dcfg->hash_method) = re; return NULL; } @@ -3203,19 +3203,19 @@ const command_rec module_directives[] = { ), AP_INIT_TAKE2 ( - "SecEncryptionMethodPm", - cmd_encryption_method_pm, + "SecHashMethodPm", + cmd_hash_method_pm, NULL, CMD_SCOPE_ANY, - "Encryption method and pattern" + "Hash method and pattern" ), AP_INIT_TAKE2 ( - "SecEncryptionMethodRx", - cmd_encryption_method_rx, + "SecHashMethodRx", + cmd_hash_method_rx, NULL, CMD_SCOPE_ANY, - "Encryption method and regex" + "Hash method and regex" ), AP_INIT_TAKE2 ( @@ -3324,27 +3324,27 @@ const command_rec module_directives[] = { ), AP_INIT_TAKE1 ( - "SecEncryptionEngine", - cmd_encryption_engine, + "SecHashEngine", + cmd_hash_engine, NULL, CMD_SCOPE_ANY, "On or Off" ), AP_INIT_TAKE2 ( - "SecEncryptionKey", - cmd_encryption_key, + "SecHashKey", + cmd_hash_key, NULL, CMD_SCOPE_ANY, - "Set Encrytion key" + "Set Hash key" ), AP_INIT_TAKE1 ( - "SecEncryptionParam", - cmd_encryption_param, + "SecHashParam", + cmd_hash_param, NULL, CMD_SCOPE_ANY, - "Set Encryption parameter" + "Set Hash parameter" ), { NULL } diff --git a/apache2/apache2_io.c b/apache2/apache2_io.c index 980acaf3ac..e6f28b75fb 100644 --- a/apache2/apache2_io.c +++ b/apache2/apache2_io.c @@ -577,7 +577,7 @@ static int flatten_response_body(modsec_rec *msr) { msr->resbody_data[msr->resbody_length] = '\0'; msr->resbody_status = RESBODY_STATUS_READ; - if (msr->txcfg->stream_outbody_inspection && msr->txcfg->encryption_is_enabled == ENCRYPTION_DISABLED) { + if (msr->txcfg->stream_outbody_inspection && msr->txcfg->hash_is_enabled == HASH_DISABLED) { msr->stream_output_length = msr->resbody_length; @@ -590,18 +590,18 @@ static int flatten_response_body(modsec_rec *msr) { memset(msr->stream_output_data, 0, msr->stream_output_length+1); strncpy(msr->stream_output_data, msr->resbody_data, msr->stream_output_length); msr->stream_output_data[msr->stream_output_length] = '\0'; - } else if (msr->txcfg->stream_outbody_inspection && msr->txcfg->encryption_is_enabled == ENCRYPTION_ENABLED) { + } else if (msr->txcfg->stream_outbody_inspection && msr->txcfg->hash_is_enabled == HASH_ENABLED) { int retval = 0; apr_time_t time1 = apr_time_now(); retval = init_response_body_html_parser(msr); if(retval == 1) { - retval = encrypt_response_body_links(msr); + retval = hash_response_body_links(msr); if(retval > 0) { - retval = inject_encrypted_response_body(msr, retval); + retval = inject_hashed_response_body(msr, retval); if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "Encryption completed in %" APR_TIME_T_FMT " usec.", (apr_time_now() - time1)); + msr_log(msr, 4, "Hash completed in %" APR_TIME_T_FMT " usec.", (apr_time_now() - time1)); } } diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index 5fb01e86bd..8eb8af88fc 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -23,7 +23,7 @@ #include typedef struct rule_exception rule_exception; -typedef struct rule_exception encryption_method; +typedef struct rule_exception hash_method; typedef struct modsec_rec modsec_rec; typedef struct directory_config directory_config; typedef struct error_message_t error_message_t; @@ -182,23 +182,23 @@ extern DSOLOCAL int *unicode_map_table; #define MODSEC_DETECTION_ONLY 1 #define MODSEC_ENABLED 2 -#define ENCRYPTION_DISABLED 0 -#define ENCRYPTION_ENABLED 1 +#define HASH_DISABLED 0 +#define HASH_ENABLED 1 -#define ENCRYPTION_URL_HREF_HASH_RX 0 -#define ENCRYPTION_URL_HREF_HASH_PM 1 -#define ENCRYPTION_URL_FACTION_HASH_RX 2 -#define ENCRYPTION_URL_FACTION_HASH_PM 3 -#define ENCRYPTION_URL_LOCATION_HASH_RX 4 -#define ENCRYPTION_URL_LOCATION_HASH_PM 5 -#define ENCRYPTION_URL_IFRAMESRC_HASH_RX 6 -#define ENCRYPTION_URL_IFRAMESRC_HASH_PM 7 -#define ENCRYPTION_URL_FRAMESRC_HASH_RX 8 -#define ENCRYPTION_URL_FRAMESRC_HASH_PM 9 +#define HASH_URL_HREF_HASH_RX 0 +#define HASH_URL_HREF_HASH_PM 1 +#define HASH_URL_FACTION_HASH_RX 2 +#define HASH_URL_FACTION_HASH_PM 3 +#define HASH_URL_LOCATION_HASH_RX 4 +#define HASH_URL_LOCATION_HASH_PM 5 +#define HASH_URL_IFRAMESRC_HASH_RX 6 +#define HASH_URL_IFRAMESRC_HASH_PM 7 +#define HASH_URL_FRAMESRC_HASH_RX 8 +#define HASH_URL_FRAMESRC_HASH_PM 9 -#define ENCRYPTION_KEYONLY 0 -#define ENCRYPTION_SESSIONID 1 -#define ENCRYPTION_REMOTEIP 2 +#define HASH_KEYONLY 0 +#define HASH_SESSIONID 1 +#define HASH_REMOTEIP 2 #define MODSEC_CACHE_DISABLED 0 #define MODSEC_CACHE_ENABLED 1 @@ -571,13 +571,13 @@ struct directory_config { /* Collection timeout */ int col_timeout; - /* Encryption */ - apr_array_header_t *encryption_method; + /* Hash */ + apr_array_header_t *hash_method; const char *crypto_key; int crypto_key_len; const char *crypto_param_name; - int encryption_is_enabled; - int encryption_enforcement; + int hash_is_enabled; + int hash_enforcement; int crypto_key_add; int crypto_hash_href_rx; int crypto_hash_faction_rx; diff --git a/apache2/msc_crypt.c b/apache2/msc_crypt.c index 7818586392..d1d810fa73 100644 --- a/apache2/msc_crypt.c +++ b/apache2/msc_crypt.c @@ -304,18 +304,18 @@ int init_response_body_html_parser(modsec_rec *msr) { } /** - * \brief Execute all encryption methods + * \brief Execute all hash methods * * \param msr ModSecurity transaction resource * \param link The html attr value to be checked - * \param type The encryption method type + * \param type The hash method type * * \retval 1 Match * \retval 0 No Match * \retval -1 on fail */ -int do_encryption_method(modsec_rec *msr, char *link, int type) { - encryption_method **em = NULL; +int do_hash_method(modsec_rec *msr, char *link, int type) { + hash_method **em = NULL; int i = 0; char *error_msg = NULL; char *my_error_msg = NULL; @@ -324,18 +324,18 @@ int do_encryption_method(modsec_rec *msr, char *link, int type) { if(msr == NULL) return -1; - em = (encryption_method **)msr->txcfg->encryption_method->elts; + em = (hash_method **)msr->txcfg->hash_method->elts; - if(msr->txcfg->encryption_method->nelts == 0) + if(msr->txcfg->hash_method->nelts == 0) return 1; - for (i = 0; i < msr->txcfg->encryption_method->nelts; i++) { + for (i = 0; i < msr->txcfg->hash_method->nelts; i++) { if(em[i] != NULL && em[i]->param_data != NULL){ switch(type) { - case ENCRYPTION_URL_HREF_HASH_PM: - if(em[i]->type == ENCRYPTION_URL_HREF_HASH_PM) { + case HASH_URL_HREF_HASH_PM: + if(em[i]->type == HASH_URL_HREF_HASH_PM) { const char *match = NULL; apr_status_t rc = 0; ACMPT pt; @@ -352,8 +352,8 @@ int do_encryption_method(modsec_rec *msr, char *link, int type) { } } break; - case ENCRYPTION_URL_HREF_HASH_RX: - if(em[i]->type == ENCRYPTION_URL_HREF_HASH_RX) { + case HASH_URL_HREF_HASH_RX: + if(em[i]->type == HASH_URL_HREF_HASH_RX) { rc = msc_regexec_capture(em[i]->param_data, link, strlen(link), ovector, 30, &my_error_msg); if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); @@ -369,7 +369,7 @@ int do_encryption_method(modsec_rec *msr, char *link, int type) { error_msg = apr_psprintf(msr->mp, "Execution error - " - "PCRE limits exceeded for Encrytion regex [%s] (%d): %s", + "PCRE limits exceeded for Hash regex [%s] (%d): %s", em[i]->param,rc, my_error_msg); if (msr->txcfg->debuglog_level >= 4) @@ -389,8 +389,8 @@ int do_encryption_method(modsec_rec *msr, char *link, int type) { } } break; - case ENCRYPTION_URL_FACTION_HASH_PM: - if(em[i]->type == ENCRYPTION_URL_FACTION_HASH_PM) { + case HASH_URL_FACTION_HASH_PM: + if(em[i]->type == HASH_URL_FACTION_HASH_PM) { const char *match = NULL; apr_status_t rc = 0; ACMPT pt; @@ -407,8 +407,8 @@ int do_encryption_method(modsec_rec *msr, char *link, int type) { } } break; - case ENCRYPTION_URL_FACTION_HASH_RX: - if(em[i]->type == ENCRYPTION_URL_FACTION_HASH_RX) { + case HASH_URL_FACTION_HASH_RX: + if(em[i]->type == HASH_URL_FACTION_HASH_RX) { rc = msc_regexec_capture(em[i]->param_data, link, strlen(link), ovector, 30, &my_error_msg); if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); @@ -424,7 +424,7 @@ int do_encryption_method(modsec_rec *msr, char *link, int type) { error_msg = apr_psprintf(msr->mp, "Execution error - " - "PCRE limits exceeded for Encrytion regex [%s] (%d): %s", + "PCRE limits exceeded for Hash regex [%s] (%d): %s", em[i]->param,rc, my_error_msg); if (msr->txcfg->debuglog_level >= 4) @@ -444,8 +444,8 @@ int do_encryption_method(modsec_rec *msr, char *link, int type) { } } break; - case ENCRYPTION_URL_LOCATION_HASH_PM: - if(em[i]->type == ENCRYPTION_URL_LOCATION_HASH_PM) { + case HASH_URL_LOCATION_HASH_PM: + if(em[i]->type == HASH_URL_LOCATION_HASH_PM) { const char *match = NULL; apr_status_t rc = 0; ACMPT pt; @@ -462,8 +462,8 @@ int do_encryption_method(modsec_rec *msr, char *link, int type) { } } break; - case ENCRYPTION_URL_LOCATION_HASH_RX: - if(em[i]->type == ENCRYPTION_URL_LOCATION_HASH_RX) { + case HASH_URL_LOCATION_HASH_RX: + if(em[i]->type == HASH_URL_LOCATION_HASH_RX) { rc = msc_regexec_capture(em[i]->param_data, link, strlen(link), ovector, 30, &my_error_msg); if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); @@ -479,7 +479,7 @@ int do_encryption_method(modsec_rec *msr, char *link, int type) { error_msg = apr_psprintf(msr->mp, "Execution error - " - "PCRE limits exceeded for Encrytion regex [%s] (%d): %s", + "PCRE limits exceeded for Hash regex [%s] (%d): %s", em[i]->param,rc, my_error_msg); if (msr->txcfg->debuglog_level >= 4) @@ -499,8 +499,8 @@ int do_encryption_method(modsec_rec *msr, char *link, int type) { } } break; - case ENCRYPTION_URL_IFRAMESRC_HASH_PM: - if(em[i]->type == ENCRYPTION_URL_IFRAMESRC_HASH_PM) { + case HASH_URL_IFRAMESRC_HASH_PM: + if(em[i]->type == HASH_URL_IFRAMESRC_HASH_PM) { const char *match = NULL; apr_status_t rc = 0; ACMPT pt; @@ -517,8 +517,8 @@ int do_encryption_method(modsec_rec *msr, char *link, int type) { } } break; - case ENCRYPTION_URL_IFRAMESRC_HASH_RX: - if(em[i]->type == ENCRYPTION_URL_IFRAMESRC_HASH_RX) { + case HASH_URL_IFRAMESRC_HASH_RX: + if(em[i]->type == HASH_URL_IFRAMESRC_HASH_RX) { rc = msc_regexec_capture(em[i]->param_data, link, strlen(link), ovector, 30, &my_error_msg); if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); @@ -534,7 +534,7 @@ int do_encryption_method(modsec_rec *msr, char *link, int type) { error_msg = apr_psprintf(msr->mp, "Execution error - " - "PCRE limits exceeded for Encrytion regex [%s] (%d): %s", + "PCRE limits exceeded for Hash regex [%s] (%d): %s", em[i]->param,rc, my_error_msg); if (msr->txcfg->debuglog_level >= 4) @@ -554,8 +554,8 @@ int do_encryption_method(modsec_rec *msr, char *link, int type) { } } break; - case ENCRYPTION_URL_FRAMESRC_HASH_PM: - if(em[i]->type == ENCRYPTION_URL_FRAMESRC_HASH_PM) { + case HASH_URL_FRAMESRC_HASH_PM: + if(em[i]->type == HASH_URL_FRAMESRC_HASH_PM) { const char *match = NULL; apr_status_t rc = 0; ACMPT pt; @@ -572,8 +572,8 @@ int do_encryption_method(modsec_rec *msr, char *link, int type) { } } break; - case ENCRYPTION_URL_FRAMESRC_HASH_RX: - if(em[i]->type == ENCRYPTION_URL_FRAMESRC_HASH_RX) { + case HASH_URL_FRAMESRC_HASH_RX: + if(em[i]->type == HASH_URL_FRAMESRC_HASH_RX) { rc = msc_regexec_capture(em[i]->param_data, link, strlen(link), ovector, 30, &my_error_msg); if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); @@ -589,7 +589,7 @@ int do_encryption_method(modsec_rec *msr, char *link, int type) { error_msg = apr_psprintf(msr->mp, "Execution error - " - "PCRE limits exceeded for Encrytion regex [%s] (%d): %s", + "PCRE limits exceeded for Hash regex [%s] (%d): %s", em[i]->param,rc, my_error_msg); if (msr->txcfg->debuglog_level >= 4) @@ -617,7 +617,7 @@ int do_encryption_method(modsec_rec *msr, char *link, int type) { } /** - * \brief Encrypt the html elements + * \brief Hash the html elements * * \param msr ModSecurity transaction resource * @@ -625,7 +625,7 @@ int do_encryption_method(modsec_rec *msr, char *link, int type) { * \retval 0 No element was changed * \retval -1 On fail */ -int encrypt_response_body_links(modsec_rec *msr) { +int hash_response_body_links(modsec_rec *msr) { int lsize = 0, fsize = 0, lcount = 0, fcount = 0, i; int isize = 0, icount = 0, frsize = 0, frcount = 0; xmlXPathContextPtr xpathCtx = NULL; @@ -639,7 +639,7 @@ int encrypt_response_body_links(modsec_rec *msr) { if (msr->crypto_html_tree == NULL) { if (msr->txcfg->debuglog_level >= 4) - msr_log(msr, 4, "encrypt_response_body_links: Cannot parse NULL html tree"); + msr_log(msr, 4, "hash_response_body_links: Cannot parse NULL html tree"); return -1; } @@ -652,7 +652,7 @@ int encrypt_response_body_links(modsec_rec *msr) { xpathCtx = xmlXPathNewContext(msr->crypto_html_tree); if(xpathCtx == NULL) { if (msr->txcfg->debuglog_level >= 4) - msr_log(msr, 4, "encrypt_response_body_links: Unable to create Xpath context."); + msr_log(msr, 4, "hash_response_body_links: Unable to create Xpath context."); goto ctx_error; } @@ -664,7 +664,7 @@ int encrypt_response_body_links(modsec_rec *msr) { if(xpathObj == NULL) { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, - "encrypt_response_body_links: Unable to evaluate xpath expression."); + "hash_response_body_links: Unable to evaluate xpath expression."); goto obj_error; } @@ -679,7 +679,7 @@ int encrypt_response_body_links(modsec_rec *msr) { if(content_href != NULL && strstr(content_href,msr->txcfg->crypto_param_name) == NULL) { if(msr->txcfg->crypto_hash_href_rx == 1) { - rc = do_encryption_method(msr, (char *)content_href, ENCRYPTION_URL_HREF_HASH_RX); + rc = do_hash_method(msr, (char *)content_href, HASH_URL_HREF_HASH_RX); if(rc > 0) { mac_link = NULL; mac_link = do_hash_link(msr, (char *)content_href, FULL_LINK); @@ -695,7 +695,7 @@ int encrypt_response_body_links(modsec_rec *msr) { } } if(msr->txcfg->crypto_hash_href_pm == 1) { - rc = do_encryption_method(msr, (char *)content_href, ENCRYPTION_URL_HREF_HASH_PM); + rc = do_hash_method(msr, (char *)content_href, HASH_URL_HREF_HASH_PM); if(rc > 0) { mac_link = NULL; mac_link = do_hash_link(msr, (char *)content_href, FULL_LINK); @@ -728,7 +728,7 @@ int encrypt_response_body_links(modsec_rec *msr) { if(xpathObj == NULL) { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, - "encrypt_response_body_links: Unable to evaluate xpath expression."); + "hash_response_body_links: Unable to evaluate xpath expression."); goto obj_error; } @@ -750,7 +750,7 @@ int encrypt_response_body_links(modsec_rec *msr) { if(content_action != NULL && content_option == NULL && strstr(content_action,msr->txcfg->crypto_param_name) == NULL) { if(msr->txcfg->crypto_hash_faction_rx == 1) { - rc = do_encryption_method(msr, (char *)content_action, ENCRYPTION_URL_FACTION_HASH_RX); + rc = do_hash_method(msr, (char *)content_action, HASH_URL_FACTION_HASH_RX); if(rc > 0) { mac_link = NULL; mac_link = do_hash_link(msr, (char *)content_action, FULL_LINK); @@ -766,7 +766,7 @@ int encrypt_response_body_links(modsec_rec *msr) { } } if(msr->txcfg->crypto_hash_faction_pm == 1) { - rc = do_encryption_method(msr, (char *)content_action, ENCRYPTION_URL_FACTION_HASH_PM); + rc = do_hash_method(msr, (char *)content_action, HASH_URL_FACTION_HASH_PM); if(rc > 0) { mac_link = NULL; mac_link = do_hash_link(msr, (char *)content_action, FULL_LINK); @@ -804,7 +804,7 @@ int encrypt_response_body_links(modsec_rec *msr) { if(xpathObj == NULL) { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, - "encrypt_response_body_links: Unable to evaluate xpath expression."); + "hash_response_body_links: Unable to evaluate xpath expression."); goto obj_error; } @@ -820,7 +820,7 @@ int encrypt_response_body_links(modsec_rec *msr) { if(content_src != NULL && strstr(content_src,msr->txcfg->crypto_param_name) == NULL) { if(msr->txcfg->crypto_hash_iframesrc_rx == 1) { - rc = do_encryption_method(msr, (char *)content_src, ENCRYPTION_URL_IFRAMESRC_HASH_RX); + rc = do_hash_method(msr, (char *)content_src, HASH_URL_IFRAMESRC_HASH_RX); if(rc > 0) { mac_link = NULL; mac_link = do_hash_link(msr, (char *)content_src, FULL_LINK); @@ -836,7 +836,7 @@ int encrypt_response_body_links(modsec_rec *msr) { } } if(msr->txcfg->crypto_hash_iframesrc_pm == 1) { - rc = do_encryption_method(msr, (char *)content_src, ENCRYPTION_URL_IFRAMESRC_HASH_PM); + rc = do_hash_method(msr, (char *)content_src, HASH_URL_IFRAMESRC_HASH_PM); if(rc > 0) { mac_link = NULL; mac_link = do_hash_link(msr, (char *)content_src, FULL_LINK); @@ -869,7 +869,7 @@ int encrypt_response_body_links(modsec_rec *msr) { if(xpathObj == NULL) { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, - "encrypt_response_body_links: Unable to evaluate xpath expression."); + "hash_response_body_links: Unable to evaluate xpath expression."); goto obj_error; } @@ -885,7 +885,7 @@ int encrypt_response_body_links(modsec_rec *msr) { if(content_src != NULL && strstr(content_src,msr->txcfg->crypto_param_name) == NULL) { if(msr->txcfg->crypto_hash_framesrc_rx == 1) { - rc = do_encryption_method(msr, (char *)content_src, ENCRYPTION_URL_FRAMESRC_HASH_RX); + rc = do_hash_method(msr, (char *)content_src, HASH_URL_FRAMESRC_HASH_RX); if(rc > 0) { mac_link = NULL; mac_link = do_hash_link(msr, (char *)content_src, FULL_LINK); @@ -901,7 +901,7 @@ int encrypt_response_body_links(modsec_rec *msr) { } } if(msr->txcfg->crypto_hash_framesrc_pm == 1) { - rc = do_encryption_method(msr, (char *)content_src, ENCRYPTION_URL_FRAMESRC_HASH_PM); + rc = do_hash_method(msr, (char *)content_src, HASH_URL_FRAMESRC_HASH_PM); if(rc > 0) { mac_link = NULL; mac_link = do_hash_link(msr, (char *)content_src, FULL_LINK); @@ -933,10 +933,10 @@ int encrypt_response_body_links(modsec_rec *msr) { xmlXPathFreeContext(xpathCtx); if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "encrypt_response_body_links: Processed [%d] iframe src, [%d] encrypted.",isize, icount); - msr_log(msr, 4, "encrypt_response_body_links: Processed [%d] frame src, [%d] encrypted.",frsize, frcount); - msr_log(msr, 4, "encrypt_response_body_links: Processed [%d] form actions, [%d] encrypted.",fsize, fcount); - msr_log(msr, 4, "encrypt_response_body_links: Processed [%d] links, [%d] encrypted.",lsize, lcount); + msr_log(msr, 4, "hash_response_body_links: Processed [%d] iframe src, [%d] hashed.",isize, icount); + msr_log(msr, 4, "hash_response_body_links: Processed [%d] frame src, [%d] hashed.",frsize, frcount); + msr_log(msr, 4, "hash_response_body_links: Processed [%d] form actions, [%d] hashed.",fsize, fcount); + msr_log(msr, 4, "hash_response_body_links: Processed [%d] links, [%d] hashed.",lsize, lcount); } if(msr->of_stream_changed == 0) { @@ -965,12 +965,12 @@ int encrypt_response_body_links(modsec_rec *msr) { * \brief Inject the new response body * * \param msr ModSecurity transaction resource - * \param elts Number of encrypted elements + * \param elts Number of hashed elements * * \retval 1 On success * \retval -1 On fail */ -int inject_encrypted_response_body(modsec_rec *msr, int elts) { +int inject_hashed_response_body(modsec_rec *msr, int elts) { xmlOutputBufferPtr output_buf = NULL; xmlCharEncodingHandlerPtr handler = NULL; char *p = NULL; @@ -984,7 +984,7 @@ int inject_encrypted_response_body(modsec_rec *msr, int elts) { if (msr->crypto_html_tree == NULL) { if (msr->txcfg->debuglog_level >= 4) - msr_log(msr, 4, "inject_encrypted_response_body: Cannot parse NULL html tree"); + msr_log(msr, 4, "inject_hashed_response_body: Cannot parse NULL html tree"); return -1; } @@ -1011,7 +1011,7 @@ int inject_encrypted_response_body(modsec_rec *msr, int elts) { } if (msr->txcfg->debuglog_level >= 4) - msr_log(msr, 4, "inject_encrypted_response_body: Detected encoding type [%s].", encoding); + msr_log(msr, 4, "inject_hashed_response_body: Detected encoding type [%s].", encoding); if (handler == NULL) handler = xmlFindCharEncodingHandler("UTF-8"); @@ -1032,12 +1032,12 @@ int inject_encrypted_response_body(modsec_rec *msr, int elts) { apr_table_set(msr->r->err_headers_out,"Content-Type",new_ct); if (msr->txcfg->debuglog_level >= 4) - msr_log(msr, 4, "inject_encrypted_response_body: Using content-type [%s].", handler->name); + msr_log(msr, 4, "inject_hashed_response_body: Using content-type [%s].", handler->name); output_buf = xmlAllocOutputBuffer(handler); if (output_buf == NULL) { if (msr->txcfg->debuglog_level >= 4) - msr_log(msr, 4, "inject_encrypted_response_body: Unable to allocate memory buffer."); + msr_log(msr, 4, "inject_hashed_response_body: Unable to allocate memory buffer."); xmlFreeDoc(msr->crypto_html_tree); return -1; } @@ -1073,7 +1073,7 @@ int inject_encrypted_response_body(modsec_rec *msr, int elts) { memcpy(msr->stream_output_data, xmlOutputBufferGetContent(output_buf), msr->stream_output_length); if (msr->txcfg->debuglog_level >= 4) - msr_log(msr, 4, "inject_encrypted_response_body: Copying XML tree from CONTENT to stream buffer [%d] bytes.", xmlOutputBufferGetSize(output_buf)); + msr_log(msr, 4, "inject_hashed_response_body: Copying XML tree from CONTENT to stream buffer [%d] bytes.", xmlOutputBufferGetSize(output_buf)); } else { @@ -1102,7 +1102,7 @@ int inject_encrypted_response_body(modsec_rec *msr, int elts) { memcpy(msr->stream_output_data, xmlOutputBufferGetContent(output_buf), msr->stream_output_length); if (msr->txcfg->debuglog_level >= 4) - msr_log(msr, 4, "inject_encrypted_response_body: Copying XML tree from CONV to stream buffer [%d] bytes.", xmlOutputBufferGetSize(output_buf)); + msr_log(msr, 4, "inject_hashed_response_body: Copying XML tree from CONV to stream buffer [%d] bytes.", xmlOutputBufferGetSize(output_buf)); } @@ -1135,7 +1135,7 @@ int inject_encrypted_response_body(modsec_rec *msr, int elts) { memcpy(msr->stream_output_data, output_buf->buffer->content, msr->stream_output_length); if (msr->txcfg->debuglog_level >= 4) - msr_log(msr, 4, "inject_encrypted_response_body: Copying XML tree from CONTENT to stream buffer [%d] bytes.", output_buf->buffer->use); + msr_log(msr, 4, "inject_hashed_response_body: Copying XML tree from CONTENT to stream buffer [%d] bytes.", output_buf->buffer->use); } else { @@ -1164,7 +1164,7 @@ int inject_encrypted_response_body(modsec_rec *msr, int elts) { memcpy(msr->stream_output_data, output_buf->conv->content, msr->stream_output_length); if (msr->txcfg->debuglog_level >= 4) - msr_log(msr, 4, "inject_encrypted_response_body: Copying XML tree from CONV to stream buffer [%d] bytes.", output_buf->conv->use); + msr_log(msr, 4, "inject_hashed_response_body: Copying XML tree from CONV to stream buffer [%d] bytes.", output_buf->conv->use); } @@ -1176,13 +1176,13 @@ int inject_encrypted_response_body(modsec_rec *msr, int elts) { apr_table_unset(msr->r->headers_out,"Content-Length"); if (msr->txcfg->debuglog_level >= 4) - msr_log(msr, 4, "inject_encrypted_response_body: Setting new content value %s", content_value); + msr_log(msr, 4, "inject_hashed_response_body: Setting new content value %s", content_value); apr_table_set(msr->r->headers_out, "Content-Length", content_value); xmlFreeDoc(msr->crypto_html_tree); if (msr->txcfg->debuglog_level >= 4) - msr_log(msr, 4, "inject_encrypted_response_body: Stream buffer [%"APR_SIZE_T_FMT"]. Done",msr->stream_output_length); + msr_log(msr, 4, "inject_hashed_response_body: Stream buffer [%"APR_SIZE_T_FMT"]. Done",msr->stream_output_length); return 1; } @@ -1192,7 +1192,7 @@ int inject_encrypted_response_body(modsec_rec *msr, int elts) { * * \param msr ModSecurity transaction resource * \param link The html attr value to be checked - * \param type The encryption method type + * \param type The hash method type * * \retval mac_link MACed link * \retval NULL on fail @@ -1211,10 +1211,10 @@ char *do_hash_link(modsec_rec *msr, char *link, int type) { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "Signing data [%s]", path_chunk+1); - if(msr->txcfg->crypto_key_add == ENCRYPTION_KEYONLY) + if(msr->txcfg->crypto_key_add == HASH_KEYONLY) hash_value = hmac(msr, msr->txcfg->crypto_key, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); - if(msr->txcfg->crypto_key_add == ENCRYPTION_SESSIONID) { + if(msr->txcfg->crypto_key_add == HASH_SESSIONID) { if(strlen(msr->sessionid) == 0) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->client_ip); @@ -1234,7 +1234,7 @@ char *do_hash_link(modsec_rec *msr, char *link, int type) { } } - if(msr->txcfg->crypto_key_add == ENCRYPTION_REMOTEIP) { + if(msr->txcfg->crypto_key_add == HASH_REMOTEIP) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->client_ip); #else @@ -1253,10 +1253,10 @@ char *do_hash_link(modsec_rec *msr, char *link, int type) { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "Signing data [%s]", path_chunk+1); - if(msr->txcfg->crypto_key_add == ENCRYPTION_KEYONLY) + if(msr->txcfg->crypto_key_add == HASH_KEYONLY) hash_value = hmac(msr, msr->txcfg->crypto_key, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); - if(msr->txcfg->crypto_key_add == ENCRYPTION_SESSIONID) { + if(msr->txcfg->crypto_key_add == HASH_SESSIONID) { if(strlen(msr->sessionid) == 0) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->client_ip); @@ -1276,7 +1276,7 @@ char *do_hash_link(modsec_rec *msr, char *link, int type) { } } - if(msr->txcfg->crypto_key_add == ENCRYPTION_REMOTEIP) { + if(msr->txcfg->crypto_key_add == HASH_REMOTEIP) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->client_ip); #else @@ -1293,10 +1293,10 @@ char *do_hash_link(modsec_rec *msr, char *link, int type) { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "Signing data [%s]", link+1); - if(msr->txcfg->crypto_key_add == ENCRYPTION_KEYONLY) + if(msr->txcfg->crypto_key_add == HASH_KEYONLY) hash_value = hmac(msr, msr->txcfg->crypto_key, msr->txcfg->crypto_key_len, (unsigned char *) link+1, strlen((char*)link)-1); - if(msr->txcfg->crypto_key_add == ENCRYPTION_SESSIONID) { + if(msr->txcfg->crypto_key_add == HASH_SESSIONID) { if(strlen(msr->sessionid) == 0) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->client_ip); @@ -1316,7 +1316,7 @@ char *do_hash_link(modsec_rec *msr, char *link, int type) { } } - if(msr->txcfg->crypto_key_add == ENCRYPTION_REMOTEIP) { + if(msr->txcfg->crypto_key_add == HASH_REMOTEIP) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->client_ip); #else @@ -1346,10 +1346,10 @@ char *do_hash_link(modsec_rec *msr, char *link, int type) { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "Signing data [%s] size %d", relative_link, strlen(relative_link)); - if(msr->txcfg->crypto_key_add == ENCRYPTION_KEYONLY) + if(msr->txcfg->crypto_key_add == HASH_KEYONLY) hash_value = hmac(msr, msr->txcfg->crypto_key, msr->txcfg->crypto_key_len, (unsigned char *) relative_link, strlen((char*)relative_link)); - if(msr->txcfg->crypto_key_add == ENCRYPTION_SESSIONID) { + if(msr->txcfg->crypto_key_add == HASH_SESSIONID) { if(strlen(msr->sessionid) == 0) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->client_ip); @@ -1369,7 +1369,7 @@ char *do_hash_link(modsec_rec *msr, char *link, int type) { } } - if(msr->txcfg->crypto_key_add == ENCRYPTION_REMOTEIP) { + if(msr->txcfg->crypto_key_add == HASH_REMOTEIP) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->client_ip); #else @@ -1430,7 +1430,7 @@ int modify_response_header(modsec_rec *msr) { msr_log(msr, 4, "Processing reponse header location [%s]", location); if(msr->txcfg->crypto_hash_location_rx == 1) { - rc = do_encryption_method(msr, (char *)location, ENCRYPTION_URL_LOCATION_HASH_RX); + rc = do_hash_method(msr, (char *)location, HASH_URL_LOCATION_HASH_RX); if(rc > 0) { mac_link = NULL; @@ -1440,7 +1440,7 @@ int modify_response_header(modsec_rec *msr) { } } else if(msr->txcfg->crypto_hash_location_pm == 1) { - rc = do_encryption_method(msr, (char *)location, ENCRYPTION_URL_LOCATION_HASH_PM); + rc = do_hash_method(msr, (char *)location, HASH_URL_LOCATION_HASH_PM); if(rc > 0) { mac_link = NULL; diff --git a/apache2/msc_crypt.h b/apache2/msc_crypt.h index 94bb99319a..54a6dc7fb5 100644 --- a/apache2/msc_crypt.h +++ b/apache2/msc_crypt.h @@ -27,11 +27,6 @@ #define INT32_MAX (2147483647) #endif -#define N16BITS_MASK 65536L -#define N16BITS_MAX 0xFFFF -#define N15BITS_MASK 0x7FFF -#define N31BITS_MASK 0x7FFFFFFF - char DSOLOCAL *hmac(modsec_rec *msr, const char *key, int key_len, unsigned char *msg, int msglen); char DSOLOCAL *do_hash_link(modsec_rec *msr, char *link, @@ -39,9 +34,9 @@ char DSOLOCAL *do_hash_link(modsec_rec *msr, char *link, char DSOLOCAL *getkey(apr_pool_t *mp); int DSOLOCAL init_response_body_html_parser(modsec_rec *msr); -int DSOLOCAL encrypt_response_body_links(modsec_rec *msr); -int DSOLOCAL inject_encrypted_response_body(modsec_rec *msr, int elts); -int DSOLOCAL do_encryption_method(modsec_rec *msr, char *link, int type); +int DSOLOCAL hash_response_body_links(modsec_rec *msr); +int DSOLOCAL inject_hashed_response_body(modsec_rec *msr, int elts); +int DSOLOCAL do_hash_method(modsec_rec *msr, char *link, int type); int DSOLOCAL modify_response_header(modsec_rec *msr); char DSOLOCAL *normalize_path(modsec_rec *msr, char *input); #endif diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 8b560d4b08..b2f2e445a2 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -229,7 +229,11 @@ static char *construct_auditlog_filename(apr_pool_t *mp, const char *uniqueid) { * as an audit log boundary. */ static char *create_auditlog_boundary(request_rec *r) { +#ifdef LINUX_S390 + int data = swap_int32(rand()); +#else unsigned long data = rand(); +#endif /* Do note that I tried using apr_generate_random_bytes but it turned * out to be terribly slow for some reason. Needs further investigation. */ diff --git a/apache2/msc_util.c b/apache2/msc_util.c index bb2d3457e0..8f9d3d0e4d 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -74,6 +74,15 @@ static unsigned char *c2x(unsigned what, unsigned char *where); static unsigned char x2c(unsigned char *what); static unsigned char xsingle2c(unsigned char *what); +#ifdef LINUX_S390 +int swap_int32(int x) { + int swap = ((x>>24)&0xff) | ((x<<8)&0xff0000) | + ((x>>8)&0xff00) | ((x<<24)&0xff000000); + return swap; +} +#endif + + /** \brief Decode utf-8 to unicode format. * * \param mp Pointer to memory pool diff --git a/apache2/msc_util.h b/apache2/msc_util.h index 76227df881..06fa26c5af 100644 --- a/apache2/msc_util.h +++ b/apache2/msc_util.h @@ -46,6 +46,11 @@ int DSOLOCAL inet_pton(int family, const char *src, void *dst); #define UNICODE_ERROR_RESTRICTED_CHARACTER -4 #define UNICODE_ERROR_DECODING_ERROR -5 +#ifdef LINUX_S390 +int DSOLOCAL swap_int32(int x); +#endif + + char DSOLOCAL *utf8_unicode_inplace_ex(apr_pool_t *mp, unsigned char *input, long int input_len, int *changed); char DSOLOCAL *m_strcasestr(const char *haystack, const char *needle); diff --git a/apache2/re_actions.c b/apache2/re_actions.c index eceb822657..ca6d59054c 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -921,15 +921,15 @@ static char *msre_action_ctl_validate(msre_engine *engine, msre_action *action) } return NULL; } else - if (strcasecmp(name, "EncryptionEnforcement") == 0) { + if (strcasecmp(name, "HashEnforcement") == 0) { if (strcasecmp(value, "on") == 0) return NULL; if (strcasecmp(value, "off") == 0) return NULL; - return apr_psprintf(engine->mp, "Invalid setting for ctl name EncryptionEnforcement: %s", value); + return apr_psprintf(engine->mp, "Invalid setting for ctl name HashEnforcement: %s", value); } else - if (strcasecmp(name, "EncryptionEngine") == 0) { + if (strcasecmp(name, "HashEngine") == 0) { if (strcasecmp(value, "on") == 0) return NULL; if (strcasecmp(value, "off") == 0) return NULL; - return apr_psprintf(engine->mp, "Invalid setting for ctl name EncryptionEngine: %s", value); + return apr_psprintf(engine->mp, "Invalid setting for ctl name HashEngine: %s", value); } else { return apr_psprintf(engine->mp, "Invalid ctl name setting: %s", name); } @@ -979,31 +979,31 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, return 1; } else - if (strcasecmp(name, "EncryptionEnforcement") == 0) { + if (strcasecmp(name, "HashEnforcement") == 0) { if (strcasecmp(value, "on") == 0) { - msr->txcfg->encryption_enforcement = ENCRYPTION_ENABLED; - msr->usercfg->encryption_enforcement = ENCRYPTION_ENABLED; + msr->txcfg->hash_enforcement = HASH_ENABLED; + msr->usercfg->hash_enforcement = HASH_ENABLED; } if (strcasecmp(value, "off") == 0) { - msr->txcfg->encryption_enforcement = ENCRYPTION_DISABLED; - msr->usercfg->encryption_enforcement = ENCRYPTION_DISABLED; + msr->txcfg->hash_enforcement = HASH_DISABLED; + msr->usercfg->hash_enforcement = HASH_DISABLED; } if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "Ctl: Set EncryptionEnforcement to %s.", value); + msr_log(msr, 4, "Ctl: Set HashEnforcement to %s.", value); } return 1; } else - if (strcasecmp(name, "EncryptionEngine") == 0) { + if (strcasecmp(name, "HashEngine") == 0) { if (strcasecmp(value, "on") == 0) { - msr->txcfg->encryption_is_enabled = ENCRYPTION_ENABLED; - msr->usercfg->encryption_is_enabled = ENCRYPTION_ENABLED; + msr->txcfg->hash_is_enabled = HASH_ENABLED; + msr->usercfg->hash_is_enabled = HASH_ENABLED; } if (strcasecmp(value, "off") == 0) { - msr->txcfg->encryption_is_enabled = ENCRYPTION_DISABLED; - msr->usercfg->encryption_is_enabled = ENCRYPTION_DISABLED; + msr->txcfg->hash_is_enabled = HASH_DISABLED; + msr->usercfg->hash_is_enabled = HASH_DISABLED; } if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "Ctl: Set EncryptionEngine to %s.", value); + msr_log(msr, 4, "Ctl: Set HashEngine to %s.", value); } return 1; } else @@ -1016,7 +1016,7 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, return 1; } else if (strcasecmp(name, "ruleRemoveByTag") == 0) { - rule_exception *re = apr_pcalloc(mptmp, sizeof(rule_exception)); + rule_exception *re = apr_pcalloc(msr->mp, sizeof(rule_exception)); re->type = RULE_EXCEPTION_REMOVE_TAG; re->param = (const char *)apr_pstrdup(msr->mp, value); re->param_data = msc_pregcomp(msr->mp, re->param, 0, NULL, NULL); @@ -1034,7 +1034,7 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, return 1; } else if (strcasecmp(name, "ruleRemoveByMsg") == 0) { - rule_exception *re = apr_pcalloc(mptmp, sizeof(rule_exception)); + rule_exception *re = apr_pcalloc(msr->mp, sizeof(rule_exception)); re->type = RULE_EXCEPTION_REMOVE_MSG; re->param = (const char *)apr_pstrdup(msr->mp, value); re->param_data = msc_pregcomp(msr->mp, re->param, 0, NULL, NULL); diff --git a/apache2/re_operators.c b/apache2/re_operators.c index eaea360aea..e6179135cc 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -721,7 +721,7 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, #endif /* MSC_TEST */ /** - * \brief Init function to validateEncryption + * \brief Init function to validateHash * * \param rule ModSecurity rule struct * \param error_msg Error message @@ -729,7 +729,7 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, * \retval 1 On success * \retval 0 On fail */ -static int msre_op_validateEncryption_param_init(msre_rule *rule, char **error_msg) { +static int msre_op_validateHash_param_init(msre_rule *rule, char **error_msg) { const char *errptr = NULL; int erroffset; msc_regex_t *regex; @@ -778,7 +778,7 @@ static int msre_op_validateEncryption_param_init(msre_rule *rule, char **error_m } /** - * \brief Execute function to validateEncryption + * \brief Execute function to validateHash * * \param msr ModSecurity transaction resource * \param rule ModSecurity rule struct @@ -788,7 +788,7 @@ static int msre_op_validateEncryption_param_init(msre_rule *rule, char **error_m * \retval 1 On success * \retval 0 On fail */ -static int msre_op_validateEncryption_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { +static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; msc_string *re_pattern = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); const char *target; @@ -809,7 +809,7 @@ static int msre_op_validateEncryption_execute(modsec_rec *msr, msre_rule *rule, if (error_msg == NULL) return -1; *error_msg = NULL; - if (msr->txcfg->encryption_enforcement == ENCRYPTION_DISABLED || msr->txcfg->encryption_is_enabled == ENCRYPTION_DISABLED) + if (msr->txcfg->hash_enforcement == HASH_DISABLED || msr->txcfg->hash_is_enabled == HASH_DISABLED) return 0; if (regex == NULL) { @@ -926,13 +926,13 @@ static int msre_op_validateEncryption_execute(modsec_rec *msr, msre_rule *rule, if(valid == NULL) { if (msr->txcfg->debuglog_level >= 9) - msr_log(msr, 9, "Request URI without encryption parameter [%s]", target); + msr_log(msr, 9, "Request URI without hash parameter [%s]", target); if (strlen(pattern) > 252) { - *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%.252s ...\" at %s. No Encryption parameter", + *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%.252s ...\" at %s. No Hash parameter", pattern, var->name); } else { - *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%s\" at %s. No Encryption parameter", + *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%s\" at %s. No Hash parameter", pattern, var->name); } return 1; @@ -952,10 +952,10 @@ static int msre_op_validateEncryption_execute(modsec_rec *msr, msre_rule *rule, if(strcmp(hmac, hash_link) != 0) { if (strlen(pattern) > 252) { - *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%.252s ...\" at %s. Encryption parameter hash value = [%s] Requested URI hash value = [%s]", + *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%.252s ...\" at %s. Hash parameter hash value = [%s] Requested URI hash value = [%s]", pattern, var->name, hmac, hash_link); } else { - *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%s\" at %s. Encryption parameter hash value = [%s] Requested URI hash value = [%s]", + *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%s\" at %s. Hash parameter hash value = [%s] Requested URI hash value = [%s]", pattern, var->name, hmac, hash_link); } return 1; @@ -4434,9 +4434,9 @@ void msre_engine_register_default_operators(msre_engine *engine) { /* validateEncyption */ msre_engine_op_register(engine, - "validateEncryption", - msre_op_validateEncryption_param_init, - msre_op_validateEncryption_execute + "validateHash", + msre_op_validateHash_param_init, + msre_op_validateHash_execute ); /* pm */ diff --git a/build/find_pcre.m4 b/build/find_pcre.m4 index 45e13ea57d..3d6985c59e 100644 --- a/build/find_pcre.m4 +++ b/build/find_pcre.m4 @@ -10,6 +10,7 @@ PCRE_CPPFLAGS="" PCRE_CFLAGS="" PCRE_LDFLAGS="" PCRE_LDADD="" +PCRE_LD_PATH="" AC_DEFUN([CHECK_PCRE], [dnl @@ -65,6 +66,8 @@ if test -n "${pcre_path}"; then if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre CFLAGS: $PCRE_CFLAGS); fi PCRE_LDADD="`${PCRE_CONFIG} --libs`" if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre LDADD: $PCRE_LDADD); fi + PCRE_LD_PATH="/`${PCRE_CONFIG} --libs | cut -d"/" -f2,3,4,5,6 | cut -d " " -f1`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre PCRE_LD_PATH: $PCRE_LD_PATH); fi else AC_MSG_RESULT([no]) fi @@ -75,6 +78,7 @@ AC_SUBST(PCRE_CPPFLAGS) AC_SUBST(PCRE_CFLAGS) AC_SUBST(PCRE_LDFLAGS) AC_SUBST(PCRE_LDADD) +AC_SUBST(PCRE_LD_PATH) if test -z "${PCRE_VERSION}"; then AC_MSG_NOTICE([*** pcre library not found.]) diff --git a/configure.ac b/configure.ac index 703a57e959..05283b9326 100644 --- a/configure.ac +++ b/configure.ac @@ -100,6 +100,11 @@ case $host in *-*-linux*) echo "Checking plataform... Identified as Linux" linuxos=true + case "${host_cpu}" in + s390x) + cpu_type="-DLINUX_S390" + ;; + esac ;; *-*-solaris*) echo "Checking plataform... Identified as Solaris" @@ -135,6 +140,7 @@ AM_CONDITIONAL([AIX], [test x$aixos = xtrue]) AM_CONDITIONAL([HPUX], [test x$hpuxos = xtrue]) AM_CONDITIONAL([MACOSX], [test x$macos = xtrue]) AM_CONDITIONAL([LINUX], [test x$linuxos = xtrue]) +AM_CONDITIONAL([LINUX390], [test x$linuxos390 = xtrue]) AM_CONDITIONAL([SOLARIS], [test x$solarisos = xtrue]) AM_CONDITIONAL([FREEBSD], [test x$freebsdos = xtrue]) AM_CONDITIONAL([OPENBSD], [test x$openbsdos = xtrue]) @@ -627,7 +633,7 @@ else fi fi -MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api" +MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type" APXS_WRAPPER=build/apxs-wrapper APXS_EXTRA_CFLAGS="" diff --git a/doc/README.txt b/doc/README.txt new file mode 100644 index 0000000000..8bbcb73045 --- /dev/null +++ b/doc/README.txt @@ -0,0 +1,12 @@ +Please access the ModSecurity Github space to access the below documentation. + + * ModSecurity 2 Data Formats + * ModSecurity Frequently Asked Questions (FAQ) + * ModSecurity Migration Matrix + * ModSecurity Rules Language Porting Specification + * ModSecurity Wiki + * Reference Manual + * RoadMap + +https://github.com/SpiderLabs/ModSecurity/wiki/ +or http://www.modsecurity.org diff --git a/doc/Reference_Manual.html b/doc/Reference_Manual.html deleted file mode 100644 index c72cd4dae5..0000000000 --- a/doc/Reference_Manual.html +++ /dev/null @@ -1,6640 +0,0 @@ - - - - - - - - - - - - - - - SourceForge.net: Reference Manual - mod-security - - - - - - - - - - - - - - - - - - - -
-
-
- -

Reference Manual

-
-

From mod-security

-
-
Jump to: navigation, - search
-

Contents

[hide]
- -
-

ModSecurity® Reference Manual

-

Current as of v2.5.13 v2.6 and v2.7

-

Copyright © 2004-2011 Trustwave Holdings, -Inc.

-

Table of Contents

-

Introduction

-

ModSecurity is a web application firewall (WAF). With over 70% of -attacks now carried out over the web application level, organisations -need all the help they can get in making their systems secure. WAFs are -deployed to establish an increased external security layer to detect -and/or prevent attacks before they reach web applications. ModSecurity -provides protection from a range of attacks against web applications and - allows for HTTP traffic monitoring and real-time analysis with little -or no changes to existing infrastructure. -

-

HTTP Traffic Logging

-

Web servers are typically well-equipped to log traffic in a form -useful for marketing analyses, but fall short logging traffic to web -applications. In particular, most are not capable of logging the request - bodies. Your adversaries know this, and that is why most attacks are -now carried out via POST requests, rendering your systems blind. -ModSecurity makes full HTTP transaction logging possible, allowing -complete requests and responses to be logged. Its logging facilities -also allow fine-grained decisions to be made about exactly what is -logged and when, ensuring only the relevant data is recorded. As some of - the request and/or response may contain sensitive data in certain -fields, ModSecurity can be configured to mask these fields before they -are written to the audit log. -

-

Real-Time Monitoring and Attack Detection

-

In addition to providing logging facilities, ModSecurity can monitor -the HTTP traffic in real time in order to detect attacks. In this case, -ModSecurity operates as a web intrusion detection tool, allowing you to -react to suspicious events that take place at your web systems. -

-

Attack Prevention and Virtual Patching

-

ModSecurity can also act immediately to prevent attacks from reaching - your web applications. There are three commonly used approaches: -

-
  1. Negative security model. A negative security model monitors -requests for anomalies, unusual behaviour, and common web application -attacks. It keeps anomaly scores for each request, IP addresses, -application sessions, and user accounts. Requests with high anomaly -scores are either logged or rejected altogether. -
  2. Positive security model. When a positive security model is -deployed, only requests that are known to be valid are accepted, with -everything else rejected. This model requires knownledge of the web -applications you are protecting. Therefore a positive security model -works best with applications that are heavily used but rarely updated so - that maintenance of the model is minimized. -
  3. Known weaknesses and vulnerabilities. Its rule language makes -ModSecurity an ideal external patching tool. External patching -(sometimes referred to as Virtual Patching) is about reducing the window - of opportunity. Time needed to patch application vulnerabilities often -runs to weeks in many organisations. With ModSecurity, applications can -be patched from the outside, without touching the application source -code (and even without any access to it), making your systems secure -until a proper patch is applied to the application. -
-

Flexible Rule Engine

-

A flexible rule engine sits in the heart of ModSecurity. It -implements the ModSecurity Rule Language, which is a specialised -programming language designed to work with HTTP transaction data. The -ModSecurity Rule Language is designed to be easy to use, yet flexible: -common operations are simple while complex operations are possible. -Certified ModSecurity Rules, included with ModSecurity, contain a -comprehensive set of rules that implement general-purpose hardening, -protocol validation and detection of common web application security -issues. Heavily commented, these rules can be used as a learning tool. -

-

- Embedded-mode Deployment

-

ModSecurity is an embeddable web application firewall, which means it - can be deployed as part of your existing web server infrastructure -provided your web servers are Apache-based. This deployment method has -certain advantages: -

-
  1. No changes to existing network. It only takes a few minutes to -add ModSecurity to your existing web servers. And because it was -designed to be completely passive by default, you are free to deploy it -incrementally and only use the features you need. It is equally easy to -remove or deactivate it if required. -
  2. No single point of failure. Unlike with network-based -deployments, you will not be introducing a new point of failure to your -system. -
  3. Implicit load balancing and scaling. Because it works embedded -in web servers, ModSecurity will automatically take advantage of the -additional load balancing and scalability features. You will not need to - think of load balancing and scaling unless your existing system needs -them. -
  4. Minimal overhead. Because it works from inside the web server -process there is no overhead for network communication and minimal -overhead in parsing and data exchange. -
  5. No problem with encrypted or compressed content. Many IDS -systems have difficulties analysing SSL traffic. This is not a problem -for ModSecurity because it is positioned to work when the traffic is -decrypted and decompressed. -
-

- Network-based Deployment

-

ModSecurity works equally well when deployed as part of an -Apache-based reverse proxy server, and many of our customers choose to -do so. In this scenario, one installation of ModSecurity can protect any - number of web servers (even the non-Apache ones). -

-

Portability

-

ModSecurity is known to work well on a wide range of operating -systems. Our customers are successfully running it on Linux, Windows, -Solaris, FreeBSD, OpenBSD, NetBSD, AIX, Mac OS X, and HP-UX. -

-

-Licensing

-

ModSecurity is available under the Apache Software License v2 [1] -

-
Note 
ModSecurity, mod_security, ModSecurity Pro, - and ModSecurity Core Rules are trademarks or registered trademarks of -Trustwave Holdings, Inc. -
-

OWASP ModSecurity Core Rule Set (CRS) Project

-

-Overview

-

ModSecurity is a web application firewall engine that provides very -little protection on its own. In order to become useful, ModSecurity -must be configured with rules. In order to enable users to take full -advantage of ModSecurity out of the box, Trustwave's SpiderLabs created -the OWASP ModSecurity Core Rule Set (CRS) Project. Unlike intrusion -detection and prevention systems, which rely on signatures specific to -known vulnerabilities, the CRS provide generic protection from unknown -vulnerabilities often found in web applications, which are in most cases - custom coded. The CRS is heavily commented to allow it to be used as a -step-by-step deployment guide for ModSecurity. The latest rules packages - can be found at the OWASP ModSecurity CRS Project Site. -

-

Core Rules Content

-

In order to provide generic web applications protection, the CRS use -some of the following example techniques: -

-
  • HTTP protection - detecting violations of the HTTP protocol and a - locally defined usage policy. -
  • Common Web Attacks Protection - detecting common web -application security attack. -
  • Automation detection - Detecting bots, crawlers, scanners and -other surface malicious activity. -
  • Trojan Protection - Detecting access to Trojans horses. -
  • Error Hiding - Disguising error messages sent by the server. -
-

Installation for Apache

-

Prerequisites

-

ModSecurity 2.x works only with Apache 2.0.x or -higher

-

Version 2.2.x is highly recommended. -

-

mod_uniqueid

-

Make sure you have mod_unique_id installed. -mod_unique_id is packaged with Apache httpd. -

-

libapr and libapr-util

-

libapr and libapr-util - http://apr.apache.org/ -

-

-libpcre

-

http://www.pcre.org/ -

-

-libxml2

-

http://xmlsoft.org/downloads.html -

-

liblua v5.1.x

-

This library is optional and only needed if you will be using the new - Lua engine - http://www.lua.org/download.html -

-
Note 
that ModSecurity requires the dynamic -libraries. These are not built by default in the source distribution, so - the binary distribution is recommended. -
-

- libcurl v7.15.1 or higher

-

If you will be using the ModSecurity Log Collector (mlogc) to send -audit logs to a central repository, then you will also need the curl -library. -

http://curl.haxx.se/libcurl/ -

-
Note 
Many have had issues with libcurl linked -with the GnuTLS library for SSL/TLS support. It is recommended that the -openssl library be used for SSL/TLS support in libcurl. -
-

Installation Methods

-

Before you begin with installation you will need to choose your -preferred installation method. First you need to choose whether to -install the latest version of ModSecurity directly from CVS (best -features, but possibly unstable) or use the latest stable release -(recommended). If you choose a stable release, it might be possible to -install ModSecurity from binary. It is always possible to compile it -from source code. -

The following few pages will give you more information on -benefits of choosing one method over another. -

-

- SVN Access

-

If you want to access the latest version of the module you need to -get it from the svn repository. The list of changes made since the last -stable release is normally available on the web site (and in the file -CHANGES). The SVN repository for ModSecurity is hosted by SourceForge (http://www.sf.net). You can - access it directly or view if through web using this address: http://mod-security.svn.sourceforge.net/viewvc/mod-security/ - -

To download the lastest TRUNK source code to your computer you -need to execute the following command: -

git -

-
$git svn clone --prefix=svn/ https://mod-security.svn.sourceforge.net/svnroot/mod-security/m2/trunk
-
-

svn -

-
svn co https://mod-security.svn.sourceforge.net/svnroot/mod-security/m2/trunk modsecurity
-
-

For v2.6.0 and above, the installation process has changed. Follow -these steps: -

-
  1. cd into the directory - $cd modsecurity -
  2. Run autogen.sh script - $./autogen.sh -
  3. Run configure script - $./configure -
  4. Run make - $make -
  5. Run make install - $make install -
  6. Copy the new mod_security2.so file into the proper Apache -modules directory - $cp -/usr/local/modsecurity/lib/mod_security2.so /usr/local/apache/modules/ -
-

Stable Release Download

-

To download the stable release go to http://www.modsecurity.org/download/. - Binary distributions are sometimes available. If they are, they are -listed on the download page. If not download the source code -distribution. -

-

Installation Steps

-
  • Stop Apache httpd -
  • Unpack the ModSecurity archive -
  • Build -
-

Building differs for UNIX (or UNIX-like) operating systems and -Windows. -

-

UNIX

-

Run the configure script to generate a Makefile. Typically no options - are needed. -

-
./configure
-

Options are available for more customization (use ./configure --help -for a full list), but typically you will only need to specify the -location of the apxs command installed by Apache httpd with the ---with-apxs option. -

-
./configure --with-apxs=/path/to/httpd-2.x.y/bin/apxs
-
Note 
There are certain configure options that -are meant for debugging an other development use. If enabled, these -options can substantially impact performance. These options include all ---debug-* options as well as the --enable-performance-measurements -options. -
-

Compile with: -

-
make
-

Optionally test with: -

-
make CFLAGS=-DMSC_TEST test
-
Note 
This is step is still a bit experimental. -If you have problems, please send the full output and error from the -build to the support list. Most common issues are related to not finding - the required headers and/or libraries. -
-

Optionally build the ModSecurity Log Collector with: -

-
make mlogc
-

Optionally install mlogc: Review the INSTALL file included in the -apache2/mlogc-src directory in the distribution. -Install the ModSecurity module with: -

-
make install
-

- Windows (MS VC++ 8)

-

Edit Makefile.win to configure the Apache base and library paths. -Compile with: nmake -f Makefile.win -Install the ModSecurity module with: nmake -f Makefile.win install -Copy the libxml2.dll and lua5.1.dll to the Apache bin directory. -Alternatively you can follow the step below for using LoadFile to load -these libraries. -

-
Note 
Users should follow the steps present in -README_WINDOWS.txt into ModSecurity tarball. -
-

- Edit the main Apache httpd config file -(usually httpd.conf)

-

On UNIX (and Windows if you did not copy the DLLs as stated above) -you must load libxml2 and lua5.1 before ModSecurity with something like -this: -

-
LoadFile /usr/lib/libxml2.so
-LoadFile /usr/lib/liblua5.1.so
-
-

Load the ModSecurity module with: -

-
LoadModule security2_module modules/mod_security2.so
-
-

Configure ModSecurity

-

Start Apache httpd

-

You should now have ModSecurity 2.x up and running. -

-
Note 
If you have compiled Apache yourself you -might experience problems compiling ModSecurity against PCRE. This is -because Apache bundles PCRE but this library is also typically provided -by the operating system. I would expect most (all) vendor-packaged -Apache distributions to be configured to use an external PCRE library -(so this should not be a problem). -
-
You want to avoid Apache using the bundled PCRE library and -ModSecurity linking against the one provided by the operating system. -The easiest way to do this is to compile Apache against the PCRE library - provided by the operating system (or you can compile it against the -latest PCRE version you downloaded from the main PCRE distribution -site). You can do this at configure time using the --with-pcre switch. -If you are not in a position to recompile Apache, then, to compile -ModSecurity successfully, you'd still need to have access to the bundled - PCRE headers (they are available only in the Apache source code) and -change the include path for ModSecurity (as you did in step 7 above) to -point to them (via the --with-pcre ModSecurity configure option). -
-
Do note that if your Apache is using an external PCRE library -you can compile ModSecurity with WITH_PCRE_STUDY defined,which would -possibly give you a slight performance edge in regular expression -processing. -
-
Non-gcc compilers may have problems running out-of-the-box as -the current build system was designed around the gcc compiler and some -compiler/linker flags may differ. To use a non-gcc compiler you may need - some manual Makefile tweaks if issues cannot be solved by exporting -custom CFLAGS and CPPFLAGS environment variables. -
-
If you are upgrading from ModSecurity 1.x, please refer to the -migration matrix at http://www.modsecurity.org/documentation/ModSecurity-Migration-Matrix.pdf -
-
Starting with ModSecurity 2.7.0 there are a few important -configuration options -
-
  1. --enable-pcre-jit - Enables JIT support from pcre >= -8.20 that can improve regex performance. -
  2. --enable-lua-cache - Enables lua vm caching that can -improve lua script performance. Difference just appears if ModSecurity -must run more than one script per transaction. -
  3. --enable-request-early - On ModSecuricy 2.6 phase one -has been moved to phase 2 hook, if you want to play around it use this -option. -
-

Installation for NGINX

-

The extensibility model of the nginx server does not include -dynamically loaded modules, thus ModSecurity must be compiled with the -source code of the main server. Since nginx is available on multiple -Unix-based platforms (and also on Windows), for now the recommended way -of obtaining ModSecurity for nginx is compilation in the designated -environment. -

-

Manually Installing ModSecurity Module on NGINX

-

The first step in obtaining nginx server with built-in ModSecurity -module is building of standalone library containing full ModSecurity -with a set of intermediate API (this layer is a common base for IIS -version, nginx version, and server-less command line version of -ModSecurity). It is recommended to follow the general steps of preparing - build environment for ModSecurity and then follow with two simple -commands -

-

Installation Steps

-

1 - Compile standalone module: -

-
~/mod_security$ ./configure --enable-standalone-module
-~/mod_security$ make
-
-

2 - Once the standalone library is built successfully, one can follow - with building the nginx server, following the steps from the nginx -build tutorial: -

-
~/nginx-1.2.0$ ./configure --add-module=../mod_security/nginx/modsecurity
-~/nginx-1.2.0$ make
-~/nginx-1.2.0$ sudo make install
-
-

The last command performs server installation on the local machine, -which can be either customized or omitted with built binaries packaged -or moved to alternative server. -

-

-Installation for Microsoft IIS

-

The source code of ModSecurity’s IIS components is fully published -and the binary building process is described (see -mod_security/iis/winbuild/howto.txt). For quick installation it is -highly recommended to use standard MSI installer available from -SourceForge files repository of ModSecurity project or use binary -package and follow the manual installation steps. -

-

- Manually Installing and Troubleshooting -Setup of ModSecurity Module on IIS

-

Prerequisites

-

Before installing ModSecurity one has to install Visual Studio 2010 -Runtime: -

- -

Installation Steps

-

Download binary package and unzip the content to a separate folder: -

- -
The installation process of ModSecurity module on IIS consists -of three parts: -
-


-

-
1. Copying of binaries: copyfiles.bat -
The following binary files are required by ModSecurity module -and by default should be copied to %windir%\system32\ (32-bit -binaries) and/or %windir%\SysWOW64\ (64-bit binaries): -
-
  • libapr-1.dll -
  • libapriconv-1.dll -
  • libaprutil-1.dll -
  • libxml2.dll -
  • lua5.1.dll -
  • ModSecurityIIS.dll -
  • pcre.dll -
  • zlib1.dll -
-
The mlogc tool can be copied to any place, together with -libcurl.dll: -
-
  • libcurl.dll -
  • mlogc.exe -
-


-

-
2. Registering of the module: register.bat -
An IIS module must be properly registered before it can be -used by web applications. The following command, executed -in %windir%\system32\inetsrv, performs the registration: -
-
appcmd.exe install module /name:ModSecurityIIS /image:%windir%\system32\inetsrv\modsecurityiis.dll
-
The registration process itself is described with details in -the following articles: -
- -


-

-
3. Extending of the configuration schema. -
The last step extends IIS configuration schema with -ModSecurity entities, using ModSecurity.xml file provided in the binary: -
-
iisschema.exe /install ModSecurity.xml
-
and iisschema.exe tool. More information about the tool and -this step is available here: -
- -

Configuration

-
After the installation the module will be running in all -websites by default. To remove it from a website add to web.config: -
-
<modules>
-    <remove name="ModSecurityIIS" />
-</modules>
-
To configure module in a website add to web.config: -
-
<?xml version="1.0" encoding="UTF-8"?>
-<configuration>
-    <system.webServer>
-        <ModSecurity enabled="true" configFile="c:\inetpub\wwwroot\xss.conf" />
-    </system.webServer>
-</configuration>
-
where configFile is standard ModSecurity config file. -
-


-

-
Events from the module will show up in "Application" Windows -log. -
-

Common Problems

-
If after installation protected website responds with HTTP 503 -error and event ID 2280 keeps getting logged in the application event -log: -
-
Log Name:      Application
-Source:        Microsoft-Windows-IIS-W3SVC-WP
-Event ID:      2280
-Task Category: None
-Level:         Error
-Keywords:      Classic
-User:          N/A
-Description:
-The Module DLL C:\Windows\system32\inetsrv\modsecurityiis.dll failed to load.  The data is the error.
-
-

most likely it means that the installation process has failed and the - ModSecurityIIS.dll module is missing one or more libraries that it -depends on. Repeating installation of the prerequisites and the module -files should fix the problem. The dependency walker tool: -

- -

can be used to figure out which library is missing or cannot be -loaded. -

-

- Configuration Directives

-

The following section outlines all of the ModSecurity directives. -Most of the ModSecurity directives can be used inside the various Apache - Scope Directives such as VirtualHost, Location, LocationMatch, -Directory, etc... There are others, however, that can only be used once -in the main configuration file. This information is specified in the -Scope sections below. The first version to use a given directive is -given in the Version sections below. -

These rules, along with the Core rules files, should be contained - is files outside of the httpd.conf file and called up with Apache -"Include" directives. This allows for easier updating/migration of the -rules. If you create your own custom rules that you would like to use -with the Core rules, you should create a file called - -modsecurity_crs_15_customrules.conf and place it in the same directory -as the Core rules files. By using this file name, your custom rules will - be called up after the standard ModSecurity Core rules configuration -file but before the other Core rules. This allows your rules to be -evaluated first which can be useful if you need to implement specific -"allow" rules or to correct any false positives in the Core rules as -they are applied to your site. -

-
Note 
It is highly encouraged that you do not -edit the Core rules files themselves but rather place all changes (such -as SecRuleRemoveByID, etc...) in your custom rules file. This will allow - for easier upgrading as newer Core rules are released by Breach -Security on the ModSecurity website. -
-

-SecAction

-

Description: Unconditionally processes the action list it -receives as the first and only parameter. The syntax of the parameter is - identical to that of the third parameter of SecRule. -

Syntax: SecAction "action1,action2,action3,...“ -

Scope: Any -

Version: 2.0.0 -

This directive is commonly used to set variables and initialize -persistent collections using the initcol action. For example: -

-
SecAction nolog,phase:1,initcol:RESOURCE=%{REQUEST_FILENAME}
-

SecArgumentSeparator

-

Description: Specifies which character to use as the separator - for application/x-www-form- urlencoded content. -

Syntax: SecArgumentSeparator character -

Default: & -

Scope: Main(< 2.7.0), Any(2.7.0) -

Version: 2.0.0 -

This directive is needed if a backend web application is using a -nonstandard argument separator. Applications are sometimes (very rarely) - written to use a semicolon separator. You should not change the default - setting unless you establish that the application you are working with -requires a different separator. If this directive is not set properly -for each web application, then ModSecurity will not be able to parse the - arguments appropriately and the effectiveness of the rule matching will - be significantly decreased. -

-

SecAuditEngine

-

Description: Configures the audit logging engine. -

Syntax: SecAuditEngine RelevantOnly -

Default: Off -

Scope: Any -

Version: 2.0.0 -

The SecAuditEngine directive is used to configure the audit -engine, which logs complete transactions. ModSecurity is currently able -to log most, but not all transactions. Transactions involving errors -(e.g., 400 and 404 transactions) use a different execution path, which -ModSecurity does not support. -

The possible values for the audit log engine are as follows: -

-
  • On: log all transactions -
  • Off: do not log any transactions -
  • RelevantOnly: only the log transactions that have -triggered a warning or an error, or have a status code that is -considered to be relevant (as determined by the -SecAuditLogRelevantStatus directive) -
-
Note 
If you need to change the audit log engine -configuration on a per-transaction basis (e.g., in response to some -transaction data), use the ctl action. -
-

The following example demonstrates how SecAuditEngine is used: -

-
SecAuditEngine RelevantOnly
-SecAuditLog logs/audit/audit.log
-SecAuditLogParts ABCFHZ 
-SecAuditLogType concurrent 
-SecAuditLogStorageDir logs/audit 
-SecAuditLogRelevantStatus ^(?:5|4(?!04))
-
-

SecAuditLog

-

Description: Defines the path to the main audit log file -(serial logging format) or the concurrent logging index file (concurrent - logging format). When used in combination with mlogc (only possible -with concurrent logging), this directive defines the mlogc location and -command line. -

Syntax: SecAuditLog /path/to/audit.log -

Scope: Any Version: 2.0.0 -

This file will be used to store the audit log entries if serial -audit logging format is used. If concurrent audit logging format is used - this file will be used as an index, and contain a record of all audit -log files created. If you are planning to use concurrent audit logging -to send your audit log data off to a remote server you will need to -deploy the ModSecurity Log Collector (mlogc), like this: -

-
SecAuditLog "|/path/to/mlogc /path/to/mlogc.conf"
-
-
Note 
This audit log file is opened on startup -when the server typically still runs as root. You should not allow -non-root users to have write privileges for this file or for the -directory. -
-

SecAuditLog2

-

Description: Defines the path to the secondary audit log index - file when concurrent logging is enabled. See SecAuditLog for more -details. -

Syntax: SecAuditLog2 /path/to/audit.log -

Scope: Any -

Version: 2.1.2 -

The purpose of SecAuditLog2 is to make logging to two remote -servers possible, which is typically achieved by running two instances -of the mlogc tool, each with a different configuration (in addition, one - of the instances will need to be instructed not to delete the files it -submits). This directive can be used only if SecAuditLog was previously -configured and only if concurrent logging format is used. -

-

SecAuditLogDirMode

-

Description: Configures the mode (permissions) of any -directories created for the concurrent audit logs, using an octal mode -value as parameter (as used in chmod). -

Syntax: SecAuditLogDirMode octal_mode|"default" - -

Default: 0600 -

Scope: Any -

Version: 2.5.10 -

The default mode for new audit log directories (0600) only grants - read/write access to the owner (typically the account under which -Apache is running, for example apache). If access from other accounts is - needed (e.g., for use with mpm-itk), then you may use this directive to - grant additional read and/or write privileges. You should use this -directive with caution to avoid exposing potentially sensitive data to -unauthorized users. Using the value default as parameter reverts the -configuration back to the default setting. This feature is not available - on operating systems not supporting octal file modes. -

Example: -

-
SecAuditLogDirMode 02750
-
Note 
The process umask may still limit the mode -if it is being more restrictive than the mode set using this directive. -
-

SecAuditLogFileMode

-

Description: Configures the mode (permissions) of any files -created for concurrent audit logs using an octal mode (as used in -chmod). See SecAuditLogDirMode for controlling the mode of created audit - log directories. -

Syntax: SecAuditLogFileMode octal_mode|"default" - -

Default: 0600 -

Scope: Any -

Version: 2.5.10 -

Example Usage: SecAuditLogFileMode 00640 -

This feature is not available on operating systems not supporting - octal file modes. The default mode (0600) only grants read/write access - to the account writing the file. If access from another account is -needed (using mpm-itk is a good example), then this directive may be -required. However, use this directive with caution to avoid exposing -potentially sensitive data to unauthorized users. Using the value -“default” will revert back to the default setting. -

-
Note 
The process umask may still limit the mode -if it is being more restrictive than the mode set using this directive. -
-

SecAuditLogParts

-

Description: Defines which parts of each transaction are going - to be recorded in the audit log. Each part is assigned a single letter; - when a letter appears in the list then the equivalent part will be -recorded. See below for the list of all parts. -

Syntax: SecAuditLogParts PARTLETTERS -

Example Usage: SecAuditLogParts ABCFHZ -

Scope: Any Version: 2.0.0 -

Default: ABCFHZ Note -

The format of the audit log format is documented in detail in the - Audit Log Data Format Documentation. -

Available audit log parts: -

-
  • A: Audit log header (mandatory). -
  • B: Request headers. -
  • C: Request body (present only if the request body exists and -ModSecurity is configured to intercept it). -
  • D: Reserved for intermediary response headers; not implemented -yet. -
  • E: Intermediary response body (present only if ModSecurity is -configured to intercept response bodies, and if the audit log engine is -configured to record it). Intermediary response body is the same as the -actual response body unless ModSecurity intercepts the intermediary -response body, in which case the actual response body will contain the -error message (either the Apache default error message, or the -ErrorDocument page). -
  • F: Final response headers (excluding the Date and Server -headers, which are always added by Apache in the late stage of content -delivery). -
  • G: Reserved for the actual response body; not implemented yet. -
  • H: Audit log trailer. -
  • I: This part is a replacement for part C. It will log the same -data as C in all cases except when multipart/form-data encoding in used. - In this case, it will log a fake application/x-www-form-urlencoded body - that contains the information about parameters but not about the files. - This is handy if you don’t want to have (often large) files stored in -your audit logs. -
  • J: This part contains information about the files uploaded -using multipart/form-data encoding. -
  • K: This part contains a full list of every rule that matched -(one per line) in the order they were matched. The rules are fully -qualified and will thus show inherited actions and default operators. -Supported as of v2.5.0. -
  • Z: Final boundary, signifies the end of the entry (mandatory). -
-

- SecAuditLogRelevantStatus

-

Description: Configures which response status code is to be -considered relevant for the purpose of audit logging. -

Syntax: SecAuditLogRelevantStatus REGEX -

Example Usage: SecAuditLogRelevantStatus -"^(?:5|4(?!04))" -

Scope: Any -

Version: 2.0.0 -

Dependencies/Notes: Must have SecAuditEngine set to -RelevantOnly. -

The main purpose of this directive is to allow you to configure -audit logging for only the transactions that have the status code that -matches the supplied regular expression. The example provided would log -all 5xx and 4xx level status codes, except for 404s. Although you could -achieve the same effect with a rule in phase 5, -SecAuditLogRelevantStatus is sometimes better, because it continues to -work even when SecRuleEngine is disabled. -

-

SecAuditLogStorageDir

-

Description: Configures the directory where concurrent audit -log entries are to be stored. -

Syntax: SecAuditLogStorageDir /path/to/storage/dir -

Example Usage: SecAuditLogStorageDir -/usr/local/apache/logs/audit -

Scope: Any -

Version: 2.0.0 -

This directive is only needed when concurrent audit logging is -used. The directory must already exist and must be writable by the web -server user. Audit log entries are created at runtime, after Apache -switches to a non-root account. -As with all logging mechanisms, ensure that you specify a file system -location that has adequate disk space and is not on the main system -partition. -

-

SecAuditLogType

-

Description: Configures the type of audit logging mechanism to - be used. -

Syntax: SecAuditLogType Serial|Concurrent -

Example Usage: SecAuditLogType Serial -

Scope: Any -

Version: 2.0.0 -

The possible values are: -

-
Serial 
Audit log entries will be stored in a -single file, specified by SecAuditLog. This is conve- nient for casual -use, but it can slow down the server, because only one audit log entry -can be written to the file at any one time. -
Concurrent 
One file per transaction is used for - audit logging. This approach is more scalable when heavy logging is -required (multiple transactions can be recorded in parallel). It is also - the only choice if you need to use remote logging. -
-

SecCacheTransformations

-

Description: Controls the caching of transformations, which -may speed up the processing of complex rule sets. Caching is off by -default starting with 2.5.6, when it was deprecated and downgraded back -to experimental. -

Syntax: SecCacheTransformations On|Off [options] -

Example Usage: SecCacheTransformations On -"minlen:64,maxlen:0" -

Scope: Any -

Version: 2.5.0; deprecated in 2.5.6. -

The first directive parameter can be one of the following: -

-
  • On: Cache transformations (per transaction, per phase) -allowing identical transforma- tions to be performed only once. -
  • Off: Do not cache any transformations, leaving all -transformations to be performed every time they are needed. -
-

The following options are allowed (multiple options must be -comma-separated): -

-
  • incremental:on|off: Enabling this option will cache every - transformation instead of just the final transformation. The default is - off. -
  • maxitems:N: Do not allow more than N transformations to -be cached. Cache will be disabled once this number is reached. A zero -value is interpreted as unlimited. This option may be useful to limit -caching for a form with a large number of variables. The default value -is 512. -
  • minlen:N: Do not cache the transformation if the -variable’s length is less than N bytes. The default setting is 32. -
  • maxlen:N: Do not cache the transformation if the -variable’s length is more than N bytes. A zero value is interpreted as -unlimited. The default setting is 1024. -
-

SecChrootDir

-

Description: Configures the directory path that will be used -to jail the web server process. -

Syntax: SecChrootDir /path/to/chroot/dir -

Example Usage: SecChrootDir /chroot -

Scope: Main -

Version: 2.0.0 -

This feature is not available on Windows builds. The internal -chroot functionality provided by ModSecurity works great for simple -setups. One example of a simple setup is Apache serving only static -files, or running applications using built-in modules. Some problems you - might encounter with more complex setups: -

-
  1. DNS lookups do not work (this is because this feature requires a - shared library that is loaded on demand, after chroot takes place). -
  2. You cannot send email from PHP, because it wants to use -sendmail and sendmail re- sides outside the jail. -
  3. In some cases, when you separate Apache from its configuration, - restarts and graceful reloads no longer work. -
-

The best way to use SecChrootDir is the following: -

-
  1. Create /chroot to be your main jail directory. -
  2. Create /chroot/opt/apache inside jail. -
  3. Create a symlink from /opt/apache to /chroot/opt/apache. -
  4. Now install Apache into /chroot/opt/apache. -
-

You should be aware that the internal chroot feature might not be -100% reliable. Due to the large number of default and third-party -modules available for the Apache web server, it is not possible to -verify the internal chroot works reliably with all of them. A module, -working from within Apache, can do things that make it easy to break out - of the jail. In particular, if you are using any of the modules that -fork in the module initialisation phase (e.g., mod_fastcgi, mod_fcgid, -mod_cgid), you are advised to examine each Apache process and observe -its current working directory, process root, and the list of open files. - Consider what your options are and make your own decision. -

-

SecComponentSignature

-

Description: Appends component signature to the ModSecurity -signature. -

Syntax: SecComponentSignature "COMPONENT_NAME/X.Y.Z -(COMMENT)" -

Example usage: SecComponentSignature "core -ruleset/2.1.3" -

Scope: Main -

Version: 2.5.0 -

This directive should be used to make the presence of significant - rule sets known. The entire signature will be recorded in the -transaction audit log. -

-

SecContentInjection

-

Description: Enables content injection using actions append -and prepend. -

Syntax: SecContentInjection On|Off -

Example Usage: SecContentInjection On -

Scope: Any -

Version: 2.5.0 -

This directive provides an easy way to control content injection, - no matter what the rules want to do. It is not necessary to have -response body buffering enabled in order to use content injection. -

-
Note 
This directive must ben enabled if you want - to use @rsub + the STREAM_ variables to manipulate live transactional -data. -
-

SecCookieFormat

-

Description: Selects the cookie format that will be used in -the current configuration context. -

Syntax: SecCookieFormat 0|1 -

Example Usage: SecCookieFormat 0 -

Scope: Any -

Version: 2.0.0 -

The possible values are: -

-
  • 0: Use version 0 (Netscape) cookies. This is what most -applications use. It is the default value. -
  • 1: Use version 1 cookies. -
-

- SecDataDir

-

Description: Path where persistent data (e.g., IP address -data, session data, and so on) is to be stored. -

Syntax: SecDataDir /path/to/dir -

Example Usage: SecDataDir -/usr/local/apache/logs/data -

Scope: Main -

Version: 2.0.0 -

This directive must be provided before initcol, setsid, and -setuid can be used. The directory to which the directive points must be -writable by the web server user. -

-

SecDebugLog

-

Description: Path to the ModSecurity debug log file. -

Syntax: SecDebugLog /path/to/modsec-debug.log -

Example Usage: SecDebugLog -/usr/local/apache/logs/modsec-debug.log -

Scope: Any -

Version: 2.0.0 -

-

SecDebugLogLevel

-

Description: Configures the verboseness of the debug log data. - -

Syntax: SecDebugLogLevel 0|1|2|3|4|5|6|7|8|9 -

Example Usage: SecDebugLogLevel 4 -

Scope: Any -

Version: 2.0.0 -

Messages at levels 1–3 are always copied to the Apache error log. - Therefore you can always use level 0 as the default logging level in -production if you are very concerned with performance. Having said that, - the best value to use is 3. Higher logging levels are not recommended -in production, because the heavy logging affects performance adversely. -

The possible values for the debug log level are: -

-
  • 0: no logging -
  • 1: errors (intercepted requests) only -
  • 2: warnings -
  • 3: notices -
  • 4: details of how transactions are handled -
  • 5: as above, but including information about each piece of -information handled -
  • 9: log everything, including very detailed debugging -information -
-

SecDefaultAction

-

Description: Defines the default list of actions, which will -be inherited by the rules in the same configuration context. -

Syntax: SecDefaultAction "action1,action2,action3“ -

Example Usage: SecDefaultAction -"phase:2,log,auditlog,deny,status:403“ -

Scope: Any -

Version: 2.0.0 -

Default: phase:2,log,auditlog,pass -

Every rule following a previous SecDefaultAction -directive in the same configuration context will inherit its settings -unless more specific actions are used. Every SecDefaultAction - directive must specify a disruptive action and a processing phase and -cannot contain metadata actions. -

-
Warning 
SecDefaultAction is not -inherited across configuration contexts. (For an example of why this may - be a problem, read the following ModSecurity Blog entry http://blog.spiderlabs.com/2008/07/three-modsecurity-rule-language-annoyances.html.) -
-

- SecDisableBackendCompression

-

Description: Disables backend compression while leaving the -frontend compression enabled. -

Syntax: SecDisableBackendCompression On|Off -

Scope: Any -

Version: 2.6.0 -

Default: Off -

This directive is necessary in reverse proxy mode when the -backend servers support response compression, but you wish to inspect -response bodies. Unless you disable backend compression, ModSecurity -will only see compressed content, which is not very useful. This -directive is not necessary in embedded mode, because ModSecurity -performs inspection before response compression takes place. -

-

SecEncryptionEngine

-

Description: Configures the encryption engine. -

Syntax: SecEncryptionEngine On|Off -

Example Usage: SecEncryptionEngine On -

Scope: Any -

Version: 2.7 -

Default: Off -

The possible values are: -

-
  • On: Encryption engine can process the request/response -data. -
  • Off: Encryption engine will not process any data. -
-
Note 
Users must enable stream output variables -and content injection. -
-

SecEncryptionKey

-

Description: Define the key that will be used by HMAC. -

Syntax: SecEncryptionKey rand|TEXT -KeyOnly|SessionID|RemoteIP -

Example Usage: SecEncryptionKey "this_is_my_key" -KeyOnly -

Scope: Any -

Version: 2.7 -

ModSecurity encryption engine will append, if specified, the -user's session id or remote ip to the key before the MAC operation. If -the first parameter is "rand" then a random key will be generated and -used by the engine. -


-

-

SecEncryptionParam

-

Description: Define the parameter name that will receive the -MAC hash. -

Syntax: SecEncryptionParam TEXT -

Example Usage: SecEncryptionKey "hmac" -

Scope: Any -

Version: 2.7 -

ModSecurity encryption engine will add a new parameter to -protected HTML elements containing the MAC hash. -

-

SecEncryptionMethodRx

-

Description: Configures what kind of HTML data the encryption -engine should sign based on regular expression. -

Syntax: SecEncryptionMethodRx TYPE REGEX -

Example Usage: SecEncryptionMethodRx HashHref -"product_info|list_product" -

Scope: Any -

Version: 2.7.0 -

As a initial support is possible to protect HREF, FRAME, IFRAME -and FORM ACTION html elements as well response Location header when http - redirect code are sent. -

The possible values for TYPE are: -

-
  • HashHref: Used to sign href= html elements -
  • HashFormAction: Used to sign form action= html elements -
  • HashIframeSrc: Used to sign iframe src= html elements -
  • HashframeSrc: Used to sign frame src= html elements -
  • HashLocation: Used to sign Location response header -
-
Note 
This directive is used to sign the elements - however user must use the @validateEncryption operator to enforce data -integrity. -
-


-

-

SecEncryptionMethodPm

-

Description: Configures what kind of HTML data the encryption -engine should sign based on string search algoritm. -

Syntax: SecEncryptionMethodRx TYPE "string1 string2 -string3..." -

Example Usage: SecEncryptionMethodRx HashHref -"product_info list_product" -

Scope: Any -

Version: 2.7.0 -

As a initial support is possible to protect HREF, FRAME, IFRAME -and FORM ACTION html elements as well response Location header when http - redirect code are sent. -

The possible values for TYPE are: -

-
  • HashHref: Used to sign href= html elements -
  • HashFormAction: Used to sign form action= html elements -
  • HashIframeSrc: Used to sign iframe src= html elements -
  • HashframeSrc: Used to sign frame src= html elements -
  • HashLocation: Used to sign Location response header -
-
Note 
This directive is used to sign the elements - however user must use the @validateEncryption operator to enforce data -integrity. -
-

SecGeoLookupDb

-

Description: Defines the path to the database that will be -used for geolocation lookups. -

Syntax: SecGeoLookupDb /path/to/db -

Example Usage: SecGeoLookupDb -/path/to/GeoLiteCity.dat -

Scope: Any -

Version: 2.5.0 -

ModSecurity relies on the free geolocation databases (GeoLite -City and GeoLite Country) that can be obtained from MaxMind [2]. -

-

SecGsbLookupDb

-

Description: Defines the path to the database that will be -used for Google Safe Browsing (GSB) lookups. -

Syntax: SecGsbLookupDb /path/to/db -

Example Usage: SecGsbLookupDb -/path/to/GsbMalware.dat -

Scope: Any -

Version: 2.6.0 -

ModSecurity relies on the free Google Safe Browsing database that - can be obtained from the Google GSB API [3]. -

-
Note 
Deprecated in 2.7.0 after Google dev team -decided to not allow the database download anymore. After registering -and obtaining a Safe Browsing API key, you can automatically download -the GSB using a tool like wget (where KEY is your own API -key): -
-

wget http://sb.google.com/safebrowsing/update?client=api&apikey=KEY&version=goog-malware-hash:1:-1 -

-

SecGuardianLog

-

Description: Configures an external program that will receive -the information about every transaction via piped logging. -

Syntax: SecGuardianLog |/path/to/httpd-guardian -

Example Usage: SecGuardianLog -|/usr/local/apache/bin/httpd-guardian -

Scope: Main -

Version: 2.0.0 -

Guardian logging is designed to send the information about every -request to an external program. Because Apache is typically deployed in a - multiprocess fashion, which makes information sharing between processes - difficult, the idea is to deploy a single external process to observe -all requests in a stateful manner, providing additional protection. -

Currently the only tool known to work with guardian logging is -httpd-guardian, which is part of the Apache httpd tools project [4]. The httpd-guardian tool is designed to defend -against denial of service attacks. It uses the blacklist tool (from the -same project) to interact with an iptables-based (on a Linux system) or -pf-based (on a BSD system) firewall, dynamically blacklisting the -offending IP addresses. It can also interact with SnortSam [5]. Assuming -httpd-guardian is already configured (look into the source code for the -detailed instructions), you only need to add one line to your Apache -configuration to deploy it: -

-
SecGuardianLog |/path/to/httpd-guardian
-

SecHttpBlKey

-

Description: Configures the user's registered Honeypot Project - HTTP BL API Key to use with @rbl. -

Syntax: SecHttpBlKey [12 char access key] -

Example Usage: SecHttpBlKey whdkfieyhtnf -

Scope: Main -

Version: 2.7.0 -

If the @rbl operator uses the dnsbl.httpbl.org RBL (http://www.projecthoneypot.org/httpbl_api.php) you -must provide an API key. This key is registered to individual users and - is included within the RBL DNS requests. -

-

SecInterceptOnError

-

Description: Configures how to respond when rule processing -fails. -

Syntax: SecInterceptOnError On|Off -

Example Usage: SecInterceptOnError On -

Scope: Main -

Version: 2.6 -

When an operator execution fails (ie returns <0), this -directive configures how to react. When set to "Off", the rule is just -ignored and the engine will continue executing the rules in phase. When - set to "On", the rule will be just dropped and no more rules will be -executed in the same phase, also no interception is made. -

-

-SecMarker

-

Description: Adds a fixed rule marker that can be used as a -target in a skipAfter action. A SecMarker directive essentially creates a - rule that does nothing and whose only purpose is to carry the given ID. -

Syntax: SecMarker ID|TEXT -

Example Usage: SecMarker 9999 -

Scope: Any -

Version: 2.5.0 -

The value can be either a number or a text string. The SecMarker - directive is available to allow you to choose the best way to implement - a skip-over. Here is an example used from the Core Rule Set: -

-
SecMarker BEGIN_HOST_CHECK
-
-        SecRule &REQUEST_HEADERS:Host "@eq 0" \
-                "skipAfter:END_HOST_CHECK,phase:2,rev:'2.1.1',t:none,block,msg:'Request Missing a Host Header',id:'960008',tag:'PROTOCOL_VIOLATION/MISSING_HEADER_HOST',tag:'WASCTC/WASC-21',tag:'OWASP_TOP_10/A7',tag:'PCI/6.5.10',severity:'5',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}"
-        SecRule REQUEST_HEADERS:Host "^$" \
-                "phase:2,rev:'2.1.1',t:none,block,msg:'Request Missing a Host Header',id:'960008',tag:'PROTOCOL_VIOLATION/MISSING_HEADER_HOST',tag:'WASCTC/WASC-21',tag:'OWASP_TOP_10/A7',tag:'PCI/6.5.10',severity:'5',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}"
-
-SecMarker END_HOST_CHECK
-
-

SecPcreMatchLimit

-

Description: Sets the match limit in the PCRE library. -

Syntax: SecPcreMatchLimit value -

Example Usage: SecPcreMatchLimit 1500 -

Scope: Main -

Version: 2.5.12 -

Default: 1500 -

The default can be changed when ModSecurity is prepared for -compilation: the --enable-pcre-match-limit=val configure option will set - a custom default and the --disable-pcre-match-limit option will revert -back to the default of the PCRE library. -For more information, refer to the pcre_extra field in the pcreapi man -page. -

-

- SecPcreMatchLimitRecursion

-

Description: Sets the match limit recursion in the PCRE -library. -

Syntax: SecPcreMatchLimitRecursion value -

Example Usage: SecPcreMatchLimitRecursion 1500 -

Scope: Main -

Version: 2.5.12 -

Default: 1500 -

The default can be changed when ModSecurity is prepared for -compilation: the --enable-pcre-match-limit-recursion=val configure -option will set a custom default and the ---disable-pcre-match-limit-recursion option will revert back to the -default of the PCRE library. -For more information, refer to the pcre_extra field in the pcreapi man -page. -

-

SecPdfProtect

-

Description: Enables the PDF XSS protection functionality. -

Syntax: SecPdfProtect On|Off -

Example Usage: SecPdfProtect On -

Scope: Any -

Version: 2.5.0; removed from trunk -

Once enabled access to PDF files is tracked. Direct access -attempts are redirected to links that contain one-time tokens. Requests -with valid tokens are allowed through, unmodified. Requests with invalid - tokens are also allowed through, but with forced download of the PDF -files. This implementation uses response headers to detect PDF files and - thus can be used with dynamically generated PDF files that do not have -the .pdf extension in the request URI. -

-

SecPdfProtectMethod

-

Description: Configure desired protection method to be used -when requests for PDF files are detected. -

Syntax: SecPdfProtectMethod method -

Example Usage: SecPdfProtectMethod TokenRedirection -

Scope: Any -

Version: 2.5.0; removed from trunk -

Default: TokenRedirection -

Possible values are TokenRedirection and ForcedDownload. The -token redirection approach will attempt to redirect with tokens where -possible. This allows PDF files to continue to be opened inline but -works only for GET requests. Forced download always causes PDF files to -be delivered as opaque binaries and attachments. The latter will always -be used for non-GET requests. Forced download is considered to be more -secure but may cause usability problems for users (“This PDF won’t open -anymore!”). -

-

SecPdfProtectSecret

-

Description: Defines the secret that will be used to construct - one-time tokens. -

Syntax: SecPdfProtectSecret secret -

Example Usage: SecPdfProtectSecret -MyRandomSecretString -

Scope: Any -

Version: 2.5.0; removed from trunk -

You should use a reasonably long value for the secret (e.g., 16 -characters is good). Once selected, the secret should not be changed, as - it will break the tokens that were sent prior to change. But it’s not a - big deal even if you change it. It will just force download of PDF -files with tokens that were issued in the last few seconds. -

-

SecPdfProtectTimeout

-

Description: Defines the token timeout. -

Syntax: SecPdfProtectTimeout timeout -

Example Usage: SecPdfProtectTimeout 10 -

Scope: Any -

Version: 2.5.0; removed from trunk -

Default: 10 -

After token expires, it can no longer be used to allow access to a - PDF file. Request will be allowed through but the PDF will be delivered - as an attachment. -

-

SecPdfProtectTokenName

-

Description: Defines the name of the token. -

Syntax: SecPdfProtectTokenName name -

Example Usage: SecPdfProtectTokenName PDFTOKEN -

Scope: Any -

Version: 2.5.0; removed from trunk -

Default: PDFTOKEN -

The only reason you would want to change the name of the token is - if you wanted to hide the fact that you are running ModSecurity. It’s a - good reason, but it won’t really help, as the adversary can look into -the algorithm used for PDF protection and figure it out anyway. It does -raise the bar slightly, so go ahead if you want to. -

-

SecReadStateLimit

-

Description: Establishes a per-IP address limit of how many -connections are allowed to be in SERVER_BUSY_READ state. -

Syntax: SecReadStateLimit LIMIT -

Example Usage: SecReadStateLimit 50 -

Scope: Main -

Version: 2.5.13 -

Default: 0 (no limit) -

This measure is effective against Slowloris-style attacks from a -single IP address, but it may not be as good against modified attacks -that work by slowly sending request body content. This is because Apache - to switches state to SERVER_BUSY_WRITE once request headers have been -read. As an alternative, consider mod_reqtimeout (part of Apache as of -2.2.15), which is expected be effective against both attack types. See -Blog post on mitigating slow DoS attacks - http://blog.spiderlabs.com/2010/11/advanced-topic-of-the-week-mitigating-slow-http-dos-attacks.html -

-

SecSensorId

-

Description: Define a sensor ID that will be present into log -part H. -

Syntax: SecSensorId TEXT -

Example Usage: SecSensorId WAFSensor01 -

Scope: Main -

Version: 2.7.0 -

-

SecWriteStateLimit

-

Description: Establishes a per-IP address limit of how many -connections are allowed to be in SERVER_BUSY_WRITE state. -

Syntax: SecWriteStateLimit LIMIT -

Example Usage: SecWriteStateLimit 50 -

Scope: Main -

Version: 2.6.0 -

Default: 0 (no limit) -

This measure is effective against Slow DoS request body attacks. -

-

SecRequestBodyAccess

-

Description: Configures whether request bodies will be -buffered and processed by ModSecurity. -

Syntax: SecRequestBodyAccess On|Off -

Example Usage: SecRequestBodyAccess On -

Scope: Any -

Version: 2.0.0 -

This directive is required if you want to inspect the data -transported request bodies (e.g., POST parameters). Request buffering is - also required in order to make reliable blocking possible. The -possible values are: -

-
  • On: buffer request bodies -
  • Off: do not buffer request bodies -
-

- SecRequestBodyInMemoryLimit

-

Description: Configures the maximum request body size that -ModSecurity will store in mem- ory. -

Syntax: SecRequestBodyInMemoryLimit LIMIT_IN_BYTES -

Example Usage: SecRequestBodyInMemoryLimit 131072 -

Scope: Any -

Version: 2.0.0 -

Default: 131072 (128 KB) -

When a multipart/form-data request is being processed, once the -in-memory limit is reached, the request body will start to be streamed -into a temporary file on disk. -

-

SecRequestBodyLimit

-

Description: Configures the maximum request body size -ModSecurity will accept for buffering. -

Syntax: SecRequestBodyLimit LIMIT_IN_BYTES -

Example Usage: SecRequestBodyLimit 134217728 -

Scope: Any -

Version: 2.0.0 -

Default: 134217728 (131072 KB) -

Anything over the limit will be rejected with status code 413 -(Request Entity Too Large). There is a hard limit of 1 GB. -

-
Note 
In ModSecurity 2.5.x and earlier, -SecRequestBodyLimit works only when used in the main server -configuration, or a VirtualHost container. In these versions, request -body limit is enforced immediately after phase 1, but before phase 2 -configuration (i.e. whatever is placed in a Location container) is -resolved. You can work around this limitation by using a phase 1 rule -that changes the request body limit dynamically, using the -ctl:requestBodyLimit action. ModSecurity 2.6.x (currently in the trunk -only) and better do not have this limitation. -
-

- SecRequestBodyNoFilesLimit

-

Description: Configures the maximum request body size -ModSecurity will accept for buffering, excluding the size of any files -being transported in the request. This directive is useful to reduce -susceptibility to DoS attacks when someone is sending request bodies of -very large sizes. Web applications that require file uploads must -configure SecRequestBodyLimit to a high value, but because large files -are streamed to disk, file uploads will not increase memory consumption. - However, it’s still possible for someone to take advantage of a large -request body limit and send non-upload requests with large body sizes. -This directive eliminates that loophole. -

Syntax: SecRequestBodyNoFilesLimit NUMBER_IN_BYTES -

Example Usage: SecRequestBodyLimit 131072 -

Scope: Any -

Version: 2.5.0 -

Default: 1048576 (1 MB) -

Generally speaking, the default value is not small enough. For -most applications, you should be able to reduce it down to 128 KB or -lower. Anything over the limit will be rejected with status code 413 -(Request Entity Too Large). There is a hard limit of 1 GB. -

-

- SecRequestBodyLimitAction

-

Description: Controls what happens once a request body limit, -configured with SecRequestBodyLimit, is encountered -

Syntax: SecRequestBodyLimitAction -Reject|ProcessPartial -

Example Usage: SecRequestBodyLimitAction -ProcessPartial -

Scope: Any -

Version: 2.6.0 -

By default, ModSecurity will reject a request body that is longer - than specified. This is problematic especially when ModSecurity is -being run in DetectionOnly mode and the intent is to be totally passive -and not take any disruptive actions against the transaction. With the -ability to choose what happens once a limit is reached, site -administrators can choose to inspect only the first part of the request, - the part that can fit into the desired limit, and let the rest through. - This is not ideal from a possible evasion issue perspective, however -it may be acceptable under certain circumstances. -

-
Note 
When the SecRuleEngine is set to -DetectionOnly, SecRequestBodyLimitAction is automatically set to -ProcessPartial in order to not cause any disruptions. If you want to -know if/when a request body size is over your limit, you can create a -rule to check for the existence of the INBOUND_ERROR_DATA variable. -
-

SecResponseBodyLimit

-

Description: Configures the maximum response body size that -will be accepted for buffering. -

Syntax: SecResponseBodyLimit LIMIT_IN_BYTES -

Example Usage: SecResponseBodyLimit 524228 -

Scope: Any -

Version: 2.0.0 -

Default: 524288 (512 KB) -

Anything over this limit will be rejected with status code 500 -(Internal Server Error). This setting will not affect the responses with - MIME types that are not selected for buffering. There is a hard limit -of 1 GB. -

-

- SecResponseBodyLimitAction

-

Description: Controls what happens once a response body limit, - configured with SecResponseBodyLimit, is encountered. -

Syntax: SecResponseBodyLimitAction -Reject|ProcessPartial -

Example Usage: SecResponseBodyLimitAction -ProcessPartial -

Scope: Any -

Version: 2.5.0 -

By default, ModSecurity will reject a response body that is -longer than specified. Some web sites, however, will produce very long -responses, making it difficult to come up with a reasonable limit. Such -sites would have to raise the limit significantly to function properly, -defying the purpose of having the limit in the first place (to control -memory consumption). With the ability to choose what happens once a -limit is reached, site administrators can choose to inspect only the -first part of the response, the part that can fit into the desired -limit, and let the rest through. Some could argue that allowing parts of - responses to go uninspected is a weakness. This is true in theory, but -applies only to cases in which the attacker controls the output (e.g., -can make it arbitrary long). In such cases, however, it is not possible -to prevent leakage anyway. The attacker could compress, obfuscate, or -even encrypt data before it is sent back, and therefore bypass any -monitoring device. -

-

SecResponseBodyMimeType

-

Description: Configures which MIME types are to be considered -for response body buffering. -

Syntax: SecResponseBodyMimeType MIMETYPE MIMETYPE -... -

Example Usage: SecResponseBodyMimeType text/plain -text/html text/xml -

Scope: Any -

Version: 2.0.0 -

Default: text/plain text/html -

Multiple SecResponseBodyMimeType directives can be used to add -MIME types. Use SecResponseBodyMimeTypesClear to clear previously -configured MIME types and start over. -

-

-SecResponseBodyMimeTypesClear

-

Description: Clears the list of MIME types considered for -response body buffering, allowing you to start populating the list from -scratch. -

Syntax: SecResponseBodyMimeTypesClear -

Example Usage: SecResponseBodyMimeTypesClear -

Scope: Any -

Version: 2.0.0 -

-

SecResponseBodyAccess

-

Description: Configures whether response bodies are to be -buffered. -

Syntax: SecResponseBodyAccess On|Off -

Example Usage: SecResponseBodyAccess On -

Scope: Any -

Version: 2.0.0 -

Default: Off -

This directive is required if you plan to inspect HTML responses -and implement response blocking. Possible values are: -

-
  • On: buffer response bodies (but only if the response MIME type -matches the list configured with SecResponseBodyMimeType). -
  • Off: do not buffer response bodies. -
-

-SecRule

-

Description: Creates a rule that will analyze the selected -variables using the selected operator. -

Syntax: SecRule VARIABLES OPERATOR [ACTIONS] -

Example Usage: SecRule ARGS "@rx attack" -"phase:1,log,deny,id:1" -

Scope: Any -

Version: 2.0.0 -

Every rule must provide one or more variables along with the -operator that should be used to inspect them. If no actions are -provided, the default list will be used. (There is always a default -list, even if one was not explicitly set with SecDefaultAction.) If -there are actions specified in a rule, they will be merged with the -default list to form the final actions that will be used. (The actions -in the rule will overwrite those in the default list.) Refer to -SecDefaultAction for more information. -

-

SecRuleInheritance

-

Description: Configures whether the current context will -inherit the rules from the parent context. -

Syntax: SecRuleInheritance On|Off -

Example Usage: SecRuleInheritance Off -

Scope: Any -

Version: 2.0.0 -

Default: On -

Sometimes when you create a more specific configuration context -(for example using the <Location> container), you may wish to use a - different set of rules than those used in the parent context. By -setting SecRuleInheritance to Off, you prevent the parent rules to be -inherited, which allows you to start from scratch. In ModSecurity 2.5.x -it is not possible to override phase 1 rules from a <Location> -configuration context. There are no limitations in that respect in the -current development version (and there won’t be in the next major -version). -

The possible values are: -

-
  • On: inherit rules from the parent context -
  • Off: do not inherit rules from the parent context -
-
Note 
Configuration contexts are an Apache -concept. Directives <Directory>, <Files>, <Location>, -and <VirtualHost> are all used to create configuration contexts. -For more information, please go to the Apache documentation, under -Configuration Sections [6]. This directive does not affect how configuration - options are inherited. -
-

SecRuleEngine

-

Description: Configures the rules engine. -

Syntax: SecRuleEngine On|Off|DetectionOnly -

Example Usage: SecRuleEngine On -

Scope: Any -

Version: 2.0.0 -

Default: Off -

The possible values are: -

-
  • On: process rules -
  • Off: do not process rules -
  • DetectionOnly: process rules but never executes any -disruptive actions (block, deny, drop, allow, proxy and redirect) -
-

SecRulePerfTime

-

Description: Set a performance threshold for rules. Rules that - spends too much time will be logged into audit log Part H in the format - id=usec. -

Syntax: SecRulePerfTime USECS -

Example Usage: SecRulePerfTime 1000 -

Scope: Any -

Version: 2.7 -

-

SecRuleRemoveById

-

Description: Removes the matching rules from the current -configuration context. -

Syntax: SecRuleRemoveById ID ID RANGE ... -

Example Usage: SecRuleRemoveByID 1 2 "9000-9010" -

Scope: Any -

Version: 2.0.0 -

This directive supports multiple parameters, each of which can be - a rule ID or a range. Parameters that contain spaces must be delimited -using double quotes. -

-
Note 
This directive must be specified after -the rule in which it is disabling. This should be used within local - custom rule files that are processed after third party rule sets. -Example file - modsecurity_crs_60_customrules.conf. -
-

SecRuleRemoveByMsg

-

Description: Removes the matching rules from the current -configuration context. -

Syntax: SecRuleRemoveByMsg REGEX -

Example Usage: SecRuleRemoveByMsg "FAIL" -

Scope: Any -

Version: 2.0.0 -

Normally, you would use SecRuleRemoveById to remove rules, but -that requires the rules to have IDs defined. If they don’t, then you can - remove them with SecRuleRemoveByMsg, which matches a regular expression - against rule messages. -

-
Note 
This directive must be specified after the -rule in which it is disabling. This should be used within local custom -rule files that are processed after third party rule sets. Example file - - modsecurity_crs_60_customrules.conf. -
-

SecRuleRemoveByTag

-

Description: Removes the matching rules from the current -configuration context. -

Syntax: SecRuleRemoveByTab REGEX -

Example Usage: SecRuleRemoveByTag "WEB_ATTACK/XSS" -

Scope: Any -

Version: 2.6 -

Normally, you would use SecRuleRemoveById to remove rules, but -that requires the rules to have IDs defined. If they don’t, then you can - remove them with SecRuleRemoveByTag, which matches a regular expression - against rule tag data. This is useful if you want to disable entire -groups of rules based on tag data. Example tags used in the OWASP -ModSecurity CRS include: -

-
  • AUTOMATION/MALICIOUS -
  • AUTOMATION/MISC -
  • AUTOMATION/SECURITY_SCANNER -
  • LEAKAGE/SOURCE_CODE_ASP_JSP -
  • LEAKAGE/SOURCE_CODE_CF -
  • LEAKAGE/SOURCE_CODE_PHP -
  • WEB_ATTACK/CF_INJECTION -
  • WEB_ATTACK/COMMAND_INJECTION -
  • WEB_ATTACK/FILE_INJECTION -
  • WEB_ATTACK/HTTP_RESPONSE_SPLITTING -
  • WEB_ATTACK/LDAP_INJECTION -
  • WEB_ATTACK/PHP_INJECTION -
  • WEB_ATTACK/REQUEST_SMUGGLING -
  • WEB_ATTACK/SESSION_FIXATION -
  • WEB_ATTACK/SQL_INJECTION -
  • WEB_ATTACK/SSI_INJECTION -
  • WEB_ATTACK/XSS -
-
Note 
This directive must be specified after the -rule in which it is disabling. This should be used within local custom -rule files that are processed after third party rule sets. Example file - - modsecurity_crs_60_customrules.conf. -
-

SecRuleScript

-

Description: This directive creates a special rule that executes a -Lua script to decide whether to match or not. The main difference from -SecRule is that there are no targets nor operators. The script can fetch - any variable from the ModSecurity context and use any (Lua) operator to - test them. The second optional parameter is the list of actions whose -meaning is identical to that of SecRule. -

Syntax: SecRuleScript /path/to/script.lua [ACTIONS] -

Example Usage: SecRuleScript "/path/to/file.lua" -"block" -

Scope: Any -

Version: 2.5.0 -

-
Note 
All Lua scripts are compiled at -configuration time and cached in memory. To reload scripts you must -reload the entire ModSecurity configuration by restarting Apache. -
-

Example script: -

-
-- Your script must define the main entry
--- point, as below.
-function main()
-    -- Log something at level 1. Normally you shouldn't be
-    -- logging anything, especially not at level 1, but this is
-    -- just to show you can. Useful for debugging.
-    m.log(1, "Hello world!");
-
-    -- Retrieve one variable.
-    local var1 = m.getvar("REMOTE_ADDR");
-
-    -- Retrieve one variable, applying one transformation function.
-    -- The second parameter is a string.
-    local var2 = m.getvar("ARGS", "lowercase");
-
-    -- Retrieve one variable, applying several transformation functions.
-    -- The second parameter is now a list. You should note that m.getvar()
-    -- requires the use of comma to separate collection names from
-    -- variable names. This is because only one variable is returned.
-    local var3 = m.getvar("ARGS.p", { "lowercase", "compressWhitespace" } );
-
-    -- If you want this rule to match return a string
-    -- containing the error message. The message must contain the name
-    -- of the variable where the problem is located.
-    -- return "Variable ARGS:p looks suspicious!"
-
-    -- Otherwise, simply return nil.
-    return nil;
-end
-
-

In this first example we were only retrieving one variable at the -time. In this case the name of the variable is known to you. In many -cases, however, you will want to examine variables whose names you won't - know in advance, for example script parameters. -

Example showing use of m.getvars() to retrieve many variables at -once: -

-
function main()
-    -- Retrieve script parameters.
-    local d = m.getvars("ARGS", { "lowercase", "htmlEntityDecode" } );
-
-    -- Loop through the paramters.
-    for i = 1, #d do
-        -- Examine parameter value.
-        if (string.find(d[i].value, "<script")) then
-            -- Always specify the name of the variable where the
-            -- problem is located in the error message.
-            return ("Suspected XSS in variable " .. d[i].name .. ".");
-        end
-    end
-
-    -- Nothing wrong found.
-    return nil;
-end
-
-
Note 
Go to http://www.lua.org/ - to find more about the Lua programming language. The reference manual -too is available online, at http://www.lua.org/manual/5.1/. -
-
Note 
Lua support is marked as experimental as -the way the progamming interface may continue to evolve while we are -working for the best implementation style. Any user input into the -programming interface is appreciated. -
-

SecRuleUpdateActionById

-

Description: Updates the action list of the specified rule. -

Syntax: SecRuleUpdateActionById RULEID[:offset] -ACTIONLIST -

Example Usage: SecRuleUpdateActionById 12345 -"deny,status:403" -

Scope: Any -

Version: 2.6.0 -

This directive will overwrite the action list of the specified -rule with the actions provided in the second parameter. It has two -limitations: it cannot be used to change the ID or phase of a rule. Only - the actions that can appear only once are overwritten. The actions that - are allowed to appear multiple times in a list, will be appended to the - end of the list. -

-
SecRule ARGS attack "phase:2,id:12345,t:lowercase,log,pass,msg:'Message text'"
-SecRuleUpdateActionById 12345 "t:none,t:compressWhitespace,deny,status:403,msg:'New message text'"
-
-

The effective resulting rule in the previous example will be as -follows: -

-
SecRule ARGS attack "phase:2,id:12345,t:lowercase,t:none,t:compressWhitespace,deny,status:403,msg:'New Message text'"
-
-

The addition of t:none will neutralize any previous transformation -functions specified (t:lowercase, in the example). -

-
Note 
If the target rule is a chained rule, you -must currently specify chain in the SecRuleUpdateActionById action list -as well. This will be fixed in a future version. -
-

SecRuleUpdateTargetById

-

Description: Updates the target (variable) list of the -specified rule. -

Syntax: SecRuleUpdateTargetById RULEID -TARGET1[,TARGET2,TARGET3] REPLACED_TARGET -

Example Usage: SecRuleUpdateTargetById 12345 -"!ARGS:foo" -

Scope: Any -

Version: 2.6 -

This directive will append (or replace) variables to the current -target list of the specified rule with the targets provided in the -second parameter. Starting with 2.7.0 this feature supports id range. -

Explicitly Appending Targets -

This is useful for implementing exceptions where you want to -externally update a target list to exclude inspection of specific -variable(s). -

-
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "[\;\|\`]\W*?\bmail\b" \
-     "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%
-{tx.0}"
-
-SecRuleUpdateTargetById 958895 !ARGS:email
-
-

The effective resulting rule in the previous example will append the -target to the end of the variable list as follows: -

-
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/*|!ARGS:email "[\;\|\`]\W*?\bmail\b" \
-     "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%
-{tx.0}""
-
-

Explicitly Replacing Targets -

You can also entirely replace the target list to something more -appropriate for your environment. For example, lets say you want to -inspect REQUEST_URI instead of REQUEST_FILENAME, you could do this: -

-
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "[\;\|\`]\W*?\bmail\b" \
-     "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%
-{tx.0}"
-
-SecRuleUpdateTargetById 958895 REQUEST_URI REQUEST_FILENAME
-
-

The effective resulting rule in the previous example will append the -target to the end of the variable list as follows: -

-
SecRule REQUEST_URI|ARGS_NAMES|ARGS|XML:/* "[\;\|\`]\W*?\bmail\b" \
-     "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%
-{tx.0}""
-
-

Conditionally Appending Targets -

You could also do the same by using the ctl action. This is -useful if you want to only update the targets for a particular URL -

-
SecRule REQUEST_FILENAME "@streq /path/to/file.php" "phase:1,id:2,t:none,nolog,pass,ctl:ruleUpdateTargetById=958895;!ARGS:email"
-
-

Conditionally Replacing Targets -

You could also replace targets using the ctl action. For -example, lets say you want to only inspect ARGS for a particular URL: -

-
SecRule REQUEST_FILENAME "@streq /path/to/file.php" "phase:1,id:3,t:none,nolog,pass,ctl:ruleUpdateTargetById=958895;REQUEST_URI;REQUEST_FILENAME"
-
-
Note 
This ctl is deprecated and will be removed -from the code, since we cannot use it per-transaction. Please use the -new ruleRemoveTargetById ctl option if you want to remove a target or -target list per-transaction. -
-

- SecRuleUpdateTargetByMsg

-

Description: Updates the target (variable) list of the -specified rule by rule message. -

Syntax: SecRuleUpdateTargetByMsg TEXT -TARGET1[,TARGET2,TARGET3] REPLACED_TARGET -

Example Usage: SecRuleUpdateTargetByMsg "Cross-site -Scripting (XSS) Attack" "!ARGS:foo" -

Scope: Any -

Version: 2.7 -

This directive will append (or replace) variables to the current -target list of the specified rule with the targets provided in the -second parameter. -

Explicitly Appending Targets -

This is useful for implementing exceptions where you want to -externally update a target list to exclude inspection of specific -variable(s). -

-
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "[\;\|\`]\W*?\bmail\b" \
-     "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%
-{tx.0}"
-
-SecRuleUpdateTargetByMsg "System Command Injection" !ARGS:email
-
-

The effective resulting rule in the previous example will append the -target to the end of the variable list as follows: -

-
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/*|!ARGS:email "[\;\|\`]\W*?\bmail\b" \
-     "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%
-{tx.0}""
-
-

Explicitly Replacing Targets -

You can also entirely replace the target list to something more -appropriate for your environment. For example, lets say you want to -inspect REQUEST_URI instead of REQUEST_FILENAME, you could do this: -

-
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "[\;\|\`]\W*?\bmail\b" \
-     "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%
-{tx.0}"
-
-SecRuleUpdateTargetByMsg "System Command Injection" REQUEST_URI REQUEST_FILENAME
-
-

The effective resulting rule in the previous example will append the -target to the end of the variable list as follows: -

-
SecRule REQUEST_URI|ARGS_NAMES|ARGS|XML:/* "[\;\|\`]\W*?\bmail\b" \
-     "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%
-{tx.0}""
-
-

- SecRuleUpdateTargetByTag

-

Description: Updates the target (variable) list of the -specified rule by rule tag. -

Syntax: SecRuleUpdateTargetByTag TEXT -TARGET1[,TARGET2,TARGET3] REPLACED_TARGET -

Example Usage: SecRuleUpdateTargetByTag -"WEB_ATTACK/XSS" "!ARGS:foo" -

Scope: Any -

Version: 2.7 -

This directive will append (or replace) variables to the current -target list of the specified rule with the targets provided in the -second parameter. -

Explicitly Appending Targets -

This is useful for implementing exceptions where you want to -externally update a target list to exclude inspection of specific -variable(s). -

-
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "[\;\|\`]\W*?\bmail\b" \
-     "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%
-{tx.0}"
-
-SecRuleUpdateTargetByTag "WASCTC/WASC-31" !ARGS:email
-
-

The effective resulting rule in the previous example will append the -target to the end of the variable list as follows: -

-
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/*|!ARGS:email "[\;\|\`]\W*?\bmail\b" \
-     "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%
-{tx.0}""
-
-

Explicitly Replacing Targets -

You can also entirely replace the target list to something more -appropriate for your environment. For example, lets say you want to -inspect REQUEST_URI instead of REQUEST_FILENAME, you could do this: -

-
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "[\;\|\`]\W*?\bmail\b" \
-     "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%
-{tx.0}"
-
-SecRuleUpdateTargetByTag "WASCTC/WASC-31" REQUEST_URI REQUEST_FILENAME
-
-

The effective resulting rule in the previous example will append the -target to the end of the variable list as follows: -

-
SecRule REQUEST_URI|ARGS_NAMES|ARGS|XML:/* "[\;\|\`]\W*?\bmail\b" \
-     "phase:2,rev:'2.1.1',capture,t:none,t:htmlEntityDecode,t:compressWhitespace,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'958895',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%
-{tx.0}""
-
-

SecServerSignature

-

Description: Instructs ModSecurity to change the data -presented in the "Server:" response header token. -

Syntax: SecServerSignature "WEB SERVER SOFTWARE" -

Example Usage: SecServerSignature -"Microsoft-IIS/6.0" -

Scope: Main -

Version: 2.0.0 -

In order for this directive to work, you must set the Apache -ServerTokens directive to Full. ModSecurity will overwrite the server -signature data held in this memory space with the data set in this -directive. If ServerTokens is not set to Full, then the memory space is -most likely not large enough to hold the new data we are looking to -insert. -

-

- SecStreamInBodyInspection

-

Description: Configures the ability to use stream inspection -for inbound request data in a re-allocable buffer. For security reasons -we are still buffering the stream. -

Syntax: SecStreamInBodyInspection On|Off -

Example Usage: SecStreamInBodyInspection On -

Scope: Any -

Version: 2.6.0 -

Default: Off -

This feature enables the creation of the STREAM_INPUT_BODY -variable and is useful for data modification or to match data in raw -data for any content-types. -

-
Note 
This directive provides full access to -REQUEST_BODY payload data. It does not include REQUEST_URI or -REQUEST_HEADER data. Also it provides data to all kind of content types, - different than REQUEST_BODY. -
-

- SecStreamOutBodyInspection

-

Description: Configures the ability to use stream inspection -for outbound request data in a re-allocable buffer. For security -reasons we are still buffering the stream. -

Syntax: SecStreamOutBodyInspection On|Off -

Example Usage: SecStreamOutBodyInspection On -

Scope: Any -

Version: 2.6.0 -

Default: Off -

This feature enables the creation of the STREAM_OUTPUT_BODY -variable and is useful when you need to do data modification into -response body. -

-
Note 
This directive provides access to -RESPONSE_BODY payload data. It does not include RESPONSE_HEADER data. -
-

-SecTmpDir

-

Description: Configures the directory where temporary files -will be created. -

Syntax: SecTmpDir /path/to/dir -

Example Usage: SecTmpDir /tmp -

Scope: Any -

Version: 2.0.0 -

The location specified needs to be writable by the Apache user -process. This is the directory location where ModSecurity will swap data - to disk if it runs out of memory (more data than what was specified in -the SecRequestBodyInMemoryLimit directive) during inspection. -

-

SecUnicodeMapFile

-

Description: Defines the path to the file that will be used by - the urlDecodeUni transformation function to map Unicode code points -during normalization. -

Syntax: SecUnicodeMapFile /path/to/unicode.mapping -

Example Usage: SecUnicodeMapFile -/usr/local/apache/conf/crs/unicode.mapping -

Scope: Any -

Version: 2.6.1 -

-

SecUnicodeCodePage

-

Description: Defines which Unicode code point will be used by -the urlDecodeUni transformation function during normalization. -

Syntax: SecUnicodeCodePage XXXXX -

Example Usage: SecUnicodeCodePage 20127 -

Scope: Any -

Version: 2.6.1 -

-

SecUploadDir

-

Description: Configures the directory where intercepted files -will be stored. -

Syntax: SecUploadDir /path/to/dir -

Example Usage: SecUploadDir /tmp -

Scope: Any -

Version: 2.0.0 -

This directory must be on the same filesystem as the temporary -directory defined with SecTmpDir. This directive is used with -SecUploadKeepFiles. -

-

SecUploadFileLimit

-

Description: Configures the maximum number of file uploads -processed in a multipart POST. -

Syntax: SecUploadFileLimit number -

Example Usage: SecUploadFileLimit 10 -

Scope: Any -

Version: 2.5.12 -

The default is set to 100 files, but you are encouraged to reduce - this value. Any file over the limit will not be extracted and the -MULTIPART_FILE_LIMIT_EXCEEDED and MULTIPART_STRICT_ERROR flags will be -set. To prevent bypassing any file checks, you must check for one of -these flags. -

-
Note 
If the limit is exceeded, the part name and - file name will still be recorded in FILES_NAME and FILES, the file size - will be recorded in FILES_SIZES, but there will be no record in -FILES_TMPNAMES as a temporary file was not created. -
-

SecUploadFileMode

-

Description: Configures the mode (permissions) of any uploaded - files using an octal mode (as used in chmod). -

Syntax: SecUploadFileMode octal_mode|"default" -

Example Usage: SecUploadFileMode 0640 -

Scope: Any -

Version: 2.1.6 -

This feature is not available on operating systems not supporting - octal file modes. The default mode (0600) only grants read/write access - to the account writing the file. If access from another account is -needed (using clamd is a good example), then this directive may be -required. However, use this directive with caution to avoid exposing -potentially sensitive data to unauthorized users. Using the value -"default" will revert back to the default setting. -

-
Note 
The process umask may still limit the mode -if it is being more restrictive than the mode set using this directive. -
-

SecUploadKeepFiles

-

Description: Configures whether or not the intercepted files -will be kept after transaction is processed. -

Syntax: SecUploadKeepFiles On|Off|RelevantOnly -

Example Usage: SecUploadKeepFiles On -

Scope: Any -

Version: 2.0.0 -

This directive requires the storage directory to be defined -(using SecUploadDir). -

Possible values are: -

-
  • On - Keep uploaded files. -
  • Off - Do not keep uploaded files. -
  • RelevantOnly - This will keep only those files that -belong to requests that are deemed relevant. -
-

SecWebAppId

-

Description: Creates an application namespace, allowing for -separate persistent session and user storage. -

Syntax: SecWebAppId "NAME" -

Example Usage: SecWebAppId "WebApp1" -

Scope: Any -

Version: 2.0.0 -

Default: default -

Application namespaces are used to avoid collisions between -session IDs and user IDs when multiple applications are deployed on the -same server. If it isn’t used, a collision between session IDs might -occur. -

-
<VirtualHost *:80> 
-ServerName app1.example.com 
-SecWebAppId "App1" ...
-</VirtualHost>
-
-<VirtualHost *:80> 
-ServerName app2.example.com 
-SecWebAppId "App2" ...
-</VirtualHost>
-
-

In the two examples configurations shown, SecWebAppId is being used -in conjunction with the Apache VirtualHost directives. Applications -namespace information is also recorded in the audit logs (using the -WebApp-Info header of the H part). -

This directive is used to set collections timeout. For example: -

-
SecCollectionTimeout 500
-

SecCollectionTimeout

-

Description: Specifies the collections timeout. Default is -3600 seconds. -

Syntax: SecCollectionTimeout seconds -

Default: 3600 -

Scope: Any -

Version: 2.6.3 -

-

Processing Phases

-

ModSecurity 2.x allows rules to be placed in one of the following -five phases of the Apache request cycle: -

-
  • Request headers (REQUEST_HEADERS) -
  • Request body (REQUEST_BODY) -
  • Response headers (RESPONSE_HEADERS) -
  • Response body (RESPONSE_BODY) -
  • Logging (LOGGING) -
-

Below is a diagram of the standard Apache Request Cycle. In the -diagram, the 5 ModSecurity processing phases are shown. -

-

In order to select the phase a rule executes during, use the -phase action either directly in the rule or in using the -SecDefaultAction directive: -

-
SecDefaultAction "log,pass,phase:2,id:4"
-SecRule REQUEST_HEADERS:Host "!^$" "deny,phase:1,id:5"
-
-
Note 
The data available in each phase is -cumulative. This means that as you move onto later phases, you have -access to more and more data from the transaction. -
Note 
Keep in mind that rules are executed -according to phases, so even if two rules are adjacent in a -configuration file, but are set to execute in different phases, they -would not happen one after the other. The order of rules in the -configuration file is important only within the rules of each phase. -This is especially important when using the skip and skipAfter actions. -
-
Note 
The LOGGING phase is special. It is -executed at the end of each transaction no matter what happened in the -previous phases. This means it will be processed even if the request was - intercepted or the allow action was used to pass the transaction -through. -
-

Phase Request Headers

-

Rules in this phase are processed immediately after Apache completes -reading the request headers (post-read-request phase). At this point the - request body has not been read yet, meaning not all request arguments -are available. Rules should be placed in this phase if you need to have -them run early (before Apache does something with the request), to do -something before the request body has been read, determine whether or -not the request body should be buffered, or decide how you want the -request body to be processed (e.g. whether to parse it as XML or not). -

-
Note 
Rules in this phase can not leverage Apache - scope directives (Directory, Location, LocationMatch, etc...) as the -post-read-request hook does not have this information yet. The exception - here is the VirtualHost directive. If you want to use ModSecurity rules - inside Apache locations, then they should run in Phase 2. Refer to the -Apache Request Cycle/ModSecurity Processing Phases diagram. -
-

Phase Request Body

-

This is the general-purpose input analysis phase. Most of the -application-oriented rules should go here. In this phase you are -guaranteed to have received the request arguments (provided the request -body has been read). ModSecurity supports three encoding types for the -request body phase: -

-
  • application/x-www-form-urlencoded - used to transfer form - data -
  • multipart/form-data - used for file transfers -
  • text/xml - used for passing XML data -
-

Other encodings are not used by most web applications. -

-
Note 
In order to access the Request Body phase -data, you must have SecRequestBodyAccess set to On. -
-

Phase Response Headers

-

This phase takes place just before response headers are sent back to -the client. Run here if you want to observe the response before that -happens, and if you want to use the response headers to determine if you - want to buffer the response body. Note that some response status codes -(such as 404) are handled earlier in the request cycle by Apache and my -not be able to be triggered as expected. Additionally, there are some -response headers that are added by Apache at a later hook (such as Date, - Server and Connection) that we would not be able to trigger on or -sanitize. This should work appropriately in a proxy setup or within -phase:5 (logging). -

-

Phase Response Body

-

This is the general-purpose output analysis phase. At this point you -can run rules against the response body (provided it was buffered, of -course). This is the phase where you would want to inspect the outbound -HTML for information disclosure, error messages or failed authentication - text. -

-
Note 
In order to access the Response Body phase -data, you must have SecResponseBodyAccess set to On -
-

Phase Logging

-

This phase is run just before logging takes place. The rules placed -into this phase can only affect how the logging is performed. This phase - can be used to inspect the error messages logged by Apache. You cannot -deny/block connections in this phase as it is too late. This phase also -allows for inspection of other response headers that weren't available -during phase:3 or phase:4. Note that you must be careful not to inherit a - disruptive action into a rule in this phase as this is a configuration -error in ModSecurity 2.5.0 and later versions -

-

-Variables

-

The following variables are supported in ModSecurity 2.x: -

-

ARGS

-

ARGS is a collection and can be used on its own (means all arguments -including the POST Payload), with a static parameter (matches arguments -with that name), or with a regular expression (matches all arguments -with name that matches the regular expression). To look at only the -query string or body arguments, see the ARGS_GET and ARGS_POST -collections. -

Some variables are actually collections, which are expanded into -more variables at runtime. The following example will examine all -request arguments: -

SecRule ARGS dirty "id:7" -

Sometimes, however, you will want to look only at parts of a -collection. This can be achieved with the help of the selection -operator(colon). The following example will only look at the arguments -named p (do note that, in general, requests can contain multiple -arguments with the same name): -

SecRule ARGS:p dirty "id:8" -

It is also possible to specify exclusions. The following will -examine all request arguments for the word dirty, except the ones named z - (again, there can be zero or more arguments named z): -

SecRule ARGS|!ARGS:z dirty "id:9" -

There is a special operator that allows you to count how many -variables there are in a collection. The following rule will trigger if -there is more than zero arguments in the request (ignore the second -parameter for the time being): -

SecRule &ARGS !^0$ "id:10" -

And sometimes you need to look at an array of parameters, each -with a slightly different name. In this case you can specify a regular -expression in the selection operator itself. The following rule will -look into all arguments whose names begin with id_: -

SecRule ARGS:/^id_/ dirty "id:11" -

-
Note 
Using ARGS:p will not result in any -invocations against the operator if argument p does not exist. -
-

In ModSecurity 1.X, the ARGS variable stood for QUERY_STRING + -POST_PAYLOAD, whereas now it expands to individual variables. -

-

ARGS_COMBINED_SIZE

-

Contains the combined size of all request parameters. Files are -excluded from the calculation. This variable can be useful, for example, - to create a rule to ensure that the total size of the argument data is -below a certain threshold. The following rule detects a request whose -para- meters are more than 2500 bytes long: -

SecRule ARGS_COMBINED_SIZE "@gt 2500" "id:12" -

-

-ARGS_GET

-

ARGS_GET is similar to ARGS, but contains only query string -parameters. -

-

ARGS_GET_NAMES

-

ARGS_GET_NAMES is similar to ARGS_NAMES, but contains only the names -of query string parameters. -

-

- ARGS_NAMES

-

Contains all request parameter names. You can search for specific -parameter names that you want to inspect. In a positive policy scenario, - you can also whitelist (using an inverted rule with the exclamation -mark) only the authorized argument names. -This example rule allows only two argument names: p and a: -

SecRule ARGS_NAMES "!^(p|a)$" "id:13" -

-

-ARGS_POST

-

ARGS_POST is similar to ARGS, but only contains arguments from the -POST body. -

-

ARGS_POST_NAMES

-

ARGS_POST_NAMES is similar to ARGS_NAMES, but contains only the names - of request body parameters. -

-

-AUTH_TYPE

-

This variable holds the authentication method used to validate a -user, if any of the methods built into HTTP are used. In a reverse-proxy - deployment, this information will not be available if the -authentication is handled in the backend web server. -

SecRule AUTH_TYPE "Basic" "id:14" -

-

-DURATION

-

Contains the number of milliseconds elapsed since the beginning of -the current transaction. Available starting with 2.6.0. -

-
Note 
Starting with ModSecurity 2.7.0 the time is - microseconds. -
-

ENV

-

Collection that provides access to environment variables set by -ModSecurity. Requires a single parameter to specify the name of the -desired variable. -

-
# Set environment variable 
-SecRule REQUEST_FILENAME "printenv" \
-"phase:2,id:15,pass,setenv:tag=suspicious" 
-
-# Inspect environment variable
-SecRule ENV:tag "suspicious" "id:16"
-
-
Note 
Use setenv to set environment variables to -be accessed by Apache. -
-

FILES

-

Contains a collection of original file names (as they were called on -the remote user’s filesys- tem). Available only on inspected -multipart/form-data requests. -

SecRule FILES "@rx \.conf$" "id:17" -

-
Note 
Only available if files were extracted from - the request body. -
-

FILES_COMBINED_SIZE

-

Contains the total size of the files transported in request body. -Available only on inspected multipart/form-data requests. -

SecRule FILES_COMBINED_SIZE "@gt 100000" "id:18" -

-

FILES_NAMES

-

Contains a list of form fields that were used for file upload. -Available only on inspected multipart/form-data requests. -

SecRule FILES_NAMES "^upfile$" "id:19" -

-

FILES_SIZES

-

Contains a list of individual file sizes. Useful for implementing a -size limitation on individual uploaded files. Available only on -inspected multipart/form-data requests. -

SecRule FILES_SIZES "@gt 100" "id:20" -

-

FILES_TMPNAMES

-

Contains a list of temporary files’ names on the disk. Useful when -used together with @inspectFile. Available only on inspected -multipart/form-data requests. -

SecRule FILES_TMPNAMES "@inspectFile -/path/to/inspect_script.pl" "id:21" -

-

GEO

-

GEO is a collection populated by the results of the last @geoLookup -operator. The collection can be used to match geographical fields looked - from an IP address or hostname. -

Available since ModSecurity 2.5.0. -

Fields: -

-
  • COUNTRY_CODE: Two character country code. EX: US, GB, etc. -
  • COUNTRY_CODE3: Up to three character country code. -
  • COUNTRY_NAME: The full country name. -
  • COUNTRY_CONTINENT: The two character continent that the country - is located. EX: EU -
  • REGION: The two character region. For US, this is state. For -Canada, providence, etc. -
  • CITY: The city name if supported by the database. -
  • POSTAL_CODE: The postal code if supported by the database. -
  • LATITUDE: The latitude if supported by the database. -
  • LONGITUDE: The longitude if supported by the database. -
  • DMA_CODE: The metropolitan area code if supported by the -database. (US only) -
  • AREA_CODE: The phone system area code. (US only) -
-

Example: -

-
SecGeoLookupDb /usr/local/geo/data/GeoLiteCity.dat
-...
-SecRule REMOTE_ADDR "@geoLookup" "chain,id:22,drop,msg:'Non-GB IP address'"
-SecRule GEO:COUNTRY_CODE "!@streq GB"
-
-

HIGHEST_SEVERITY

-

This variable holds the highest severity of any rules that have -matched so far. Severities are numeric values and thus can be used with -comparison operators such as @lt, and so on. A value of 255 indicates -that no severity has been set. -

SecRule HIGHEST_SEVERITY "@le 2" -"phase:2,id:23,deny,status:500,msg:'severity %{HIGHEST_SEVERITY}'" -

-
Note 
Higher severities have a lower numeric -value. -
-

INBOUND_DATA_ERROR

-

This variable will be set to 1 when the request body size is above -the setting configured by SecRequestBodyLimit directive. Your policies -should always contain a rule to check this variable. Depending on the -rate of false positives and your default policy you should decide -whether to block or just warn when the rule is triggered. -

The best way to use this variable is as in the example below: -

SecRule INBOUND_DATA_ERROR "@eq 1" -"phase:1,id:24,t:none,log,pass,msg:'Request Body Larger than -SecRequestBodyLimit Setting'" -

-

MATCHED_VAR

-

This variable holds the value of the most-recently matched variable. -It is similar to the TX:0, but it is automatically supported by all -operators and there is no need to specify the capture action. -

-
SecRule ARGS pattern chain,deny,id:25
-  SecRule MATCHED_VAR "further scrutiny"
-
-
Note 
Be aware that this variable holds data for -the last operator match. This means that if there are -more than one matches, only the last one will be populated. Use -MATCHED_VARS variable if you want all matches. -
-

MATCHED_VARS

-

Similar to MATCHED_VAR except that it is a collection of all -matches for the current operator check. -

-
SecRule ARGS pattern "chain,deny,id:26"
-  SecRule MATCHED_VARS "@eq ARGS:param"
-
-

MATCHED_VAR_NAME

-

This variable holds the full name of the variable that was matched -against. -

-
SecRule ARGS pattern "chain,deny,id:27"
-  SecRule MATCHED_VAR_NAME "@eq ARGS:param"
-
-
Note 
Be aware that this variable holds data for -the last operator match. This means that if there are -more than one matches, only the last one will be populated. Use -MATCHED_VARS_NAMES variable if you want all matches. -
-

MATCHED_VARS_NAMES

-

Similar to MATCHED_VAR_NAME except that it is a collection of all - matches for the current operator check. -

-
SecRule ARGS pattern "chain,deny,id:28"
-  SecRule MATCHED_VARS_NAMES "@eq ARGS:param"
-
-

MODSEC_BUILD

-

This variable holds the ModSecurity build number. This variable is -intended to be used to check the build number prior to using a feature -that is available only in a certain build. Example: -

-
SecRule MODSEC_BUILD "!@ge 02050102" "skipAfter:12345,id:29"
-SecRule ARGS "@pm some key words" "id:12345,deny,status:500"
-
-

MULTIPART_CRLF_LF_LINES

-

This flag variable will be set to 1 whenever a multi-part request -uses mixed line terminators. The multipart/form-data RFC requires CRLF -sequence to be used to terminate lines. Since some client -implementations use only LF to terminate lines you might want to allow -them to proceed under certain circumstances (if you want to do this you -will need to stop using MULTIPART_STRICT_ERROR and check each multi-part - flag variable individually, avoiding MULTIPART_LF_LINE). However, -mixing CRLF and LF line terminators is dangerous as it can allow for -evasion. Therefore, in such cases, you will have to add a check for -MULTIPART_CRLF_LF_LINES. -

-

MULTIPART_STRICT_ERROR

-

MULTIPART_STRICT_ERROR will be set to 1 when any of the following -variables is also set to 1: REQBODY_PROCESSOR_ERROR, -MULTIPART_BOUNDARY_QUOTED, MULTIPART_BOUNDARY_WHITESPACE, -MULTIPART_DATA_BEFORE, MULTIPART_DATA_AFTER, MULTIPART_HEADER_FOLDING, -MULTIPART_LF_LINE, MULTIPART_MISSING_SEMICOLON MULTIPART_INVALID_QUOTING - MULTIPART_INVALID_HEADER_FOLDING MULTIPART_FILE_LIMIT_EXCEEDED. Each of - these variables covers one unusual (although sometimes legal) aspect of - the request body in multipart/form-data format. Your policies should -always contain a rule to check either this variable (easier) or one or -more individual variables (if you know exactly what you want to -accomplish). Depending on the rate of false positives and your default -policy you should decide whether to block or just warn when the rule is -triggered. -

The best way to use this variable is as in the example below: -

-
SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
-"phase:2,id:30,t:none,log,deny,msg:'Multipart request body \
-failed strict validation: \
-PE %{REQBODY_PROCESSOR_ERROR}, \
-BQ %{MULTIPART_BOUNDARY_QUOTED}, \
-BW %{MULTIPART_BOUNDARY_WHITESPACE}, \
-DB %{MULTIPART_DATA_BEFORE}, \
-DA %{MULTIPART_DATA_AFTER}, \
-HF %{MULTIPART_HEADER_FOLDING}, \
-LF %{MULTIPART_LF_LINE}, \
-SM %{MULTIPART_MISSING_SEMICOLON}, \
-IQ %{MULTIPART_INVALID_QUOTING}, \
-IQ %{MULTIPART_INVALID_HEADER_FOLDING}, \
-FE %{MULTIPART_FILE_LIMIT_EXCEEDED}'"
-
-

The multipart/form-data parser was upgraded in ModSecurity v2.1.3 to -actively look for signs of evasion. Many variables (as listed above) -were added to expose various facts discovered during the parsing -process. The MULTIPART_STRICT_ERROR variable is handy to check on all -abnormalities at once. The individual variables allow detection to be -fine-tuned according to your circumstances in order to reduce the number - of false positives. -

-

- MULTIPART_UNMATCHED_BOUNDARY

-

Set to 1 when, during the parsing phase of a multipart/request-body, -ModSecurity encounters what feels like a boundary but it is not. Such an - event may occur when evasion of ModSecurity is attempted. -

The best way to use this variable is as in the example below: -

-
SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \
-"phase:2,id:31,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'"
-
-

Change the rule from blocking to logging-only if many false positives - are encountered. -

-

OUTBOUND_DATA_ERROR

-

This variable will be set to 1 when the response body size is above -the setting configured by SecResponseBodyLimit directive. Your policies - should always contain a rule to check this variable. Depending on the -rate of false positives and your default policy you should decide -whether to block or just warn when the rule is triggered. -

The best way to use this variable is as in the example below: -

SecRule OUTBOUND_DATA_ERROR "@eq 1" -"phase:1,id:32,t:none,log,pass,msg:'Response Body Larger than -SecResponseBodyLimit Setting'" -

-

-PATH_INFO

-

Contains the extra request URI information, also known as path info. -(For example, in the URI /index.php/123, /123 is the path info.) -Available only in embedded deployments. -

SecRule PATH_INFO "^/(bin|etc|sbin|opt|usr)" "id:33" -

-

PERF_COMBINED

-

Contains the time, in microseconds, spent in ModSecurity during the -current transaction. The value in this variable is arrived to by adding -all the performance variables except PERF_SREAD (the time spent reading -from persistent storage is already included in the phase measurements). -Available starting with 2.6. -

-

-PERF_GC

-

Contains the time, in microseconds, spent performing garbage -collection. Available starting with 2.6. -

-

PERF_LOGGING

-

Contains the time, in microseconds, spent in audit logging. This -value is known only after the handling of a transaction is finalized, -which means that it can only be logged using mod_log_config and -the %{VARNAME}M syntax. Available starting with 2.6. -

-

PERF_PHASE1

-

Contains the time, in microseconds, spent processing phase 1. -Available starting with 2.6. -

-

PERF_PHASE2

-

Contains the time, in microseconds, spent processing phase 2. -Available starting with 2.6. -

-

PERF_PHASE3

-

Contains the time, in microseconds, spent processing phase 3. -Available starting with 2.6. -

-

PERF_PHASE4

-

Contains the time, in microseconds, spent processing phase 4. -Available starting with 2.6. -

-

PERF_PHASE5

-

Contains the time, in microseconds, spent processing phase 5. -Available starting with 2.6. -

-

- PERF_RULES

-

Contains the time of rules, in microseconds. Available starting with -2.7. -

SecRule PERF_RULES "@gt 1000" "id:12345,phase:5" -

-

- PERF_SREAD

-

Contains the time, in microseconds, spent reading from persistent -storage. Available starting with 2.6. -

-

PERF_SWRITE

-

Contains the time, in microseconds, spent writing to persistent -storage. Available starting with 2.6. -

-

QUERY_STRING

-

Contains the query string part of a request URI. The value in -QUERY_STRING is always provided raw, without URL decoding taking place. -

SecRule QUERY_STRING "attack" "id:34" -

-

REMOTE_ADDR

-

This variable holds the IP address of the remote client. -

SecRule REMOTE_ADDR "@ipMatch 192.168.1.101" "id:35" -

-

REMOTE_HOST

-

If the Apache directive HostnameLookups is set to On, then this -variable will hold the remote hostname resolved through DNS. If the -directive is set to Off, this variable it will hold the remote IP -address (same as REMOTE_ADDR). Possible uses for this variable would be -to deny known bad client hosts or network blocks, or conversely, to -allow in authorized hosts. -

SecRule REMOTE_HOST "\.evil\.network\org$" "id:36" -

-

REMOTE_PORT

-

This variable holds information on the source port that the client -used when initiating the connection to our web server. -

In the following example, we are evaluating to see whether the -REMOTE_PORT is less than 1024, which would indicate that the user is a -privileged user: -

SecRule REMOTE_PORT "@lt 1024" "id:37" -

-

REMOTE_USER

-

This variable holds the username of the authenticated user. If there -are no password access controls in place (Basic or Digest -authentication), then this variable will be empty. -

SecRule REMOTE_USER "^admin$" "id:38" -

-
Note 
In a reverse-proxy deployment, this -information will not be available if the authentication is -
-

handled in the backend web server. -

-

REQBODY_ERROR

-

Contains the status of the request body processor used for request -body parsing. The values can be 0 (no error) or 1 (error). This variable - will be set by request body processors (typically the -multipart/request-data parser or the XML parser) when they fail to do -their work. -

SecRule REQBODY_ERROR "@eq 1" deny,phase:2,id:39 -

-
Note 
Your policies must have a rule to check for - request body processor errors at the very beginning of phase 2. Failure - to do so will leave the door open for impedance mismatch attacks. It is - possible, for example, that a payload that cannot be parsed by -ModSecurity can be successfully parsed by more tolerant parser operating - in the application. If your policy dictates blocking, then you should -reject the request if error is detected. When operating in -detection-only mode, your rule should alert with high severity when -request body processing fails. -
-

REQBODY_ERROR_MSG

-

If there’s been an error during request body parsing, the variable -will contain the following error message: -

SecRule REQBODY_ERROR_MSG "failed to parse" "id:40" -

-

REQBODY_PROCESSOR

-

Contains the name of the currently used request body processor. The -possible values are URLENCODED, MULTIPART, and XML. -

-
SecRule REQBODY_PROCESSOR "^XML$ chain,id:41 
-  SecRule XML "@validateDTD /opt/apache-frontend/conf/xml.dtd"
-
-

REQUEST_BASENAME

-

This variable holds just the filename part of REQUEST_FILENAME (e.g., - index.php). -

SecRule REQUEST_BASENAME "^login\.php$" -phase:2,id:42,t:none,t:lowercase -

-
Note 
Please note that anti-evasion -transformations are not applied to this variable by default. -REQUEST_BASENAME will recognise both / and \ as path separators. You -should understand that the value of this variable depends on what was -provided in request, and that it does not have to correspond to the -resource (on disk) that will be used by the web server. -
-

REQUEST_BODY

-

Holds the raw request body. This variable is available only if the -URLENCODED request body processor was used, which will occur by default -when the application/x-www-form-urlencoded content type is detected, or -if the use of the URLENCODED request body parser was forced. -

SecRule REQUEST_BODY -"^username=\w{25,}\&password=\w{25,}\&Submit\=login$" "id:43" -

As of 2.5.7, it is possible to force the presence of the -REQUEST_BODY variable, but only when there is no request body processor -defined using the ctl:forceRequestBodyVariable option in the -REQUEST_HEADERS phase. -

-

REQUEST_BODY_LENGTH

-

Contains the number of bytes read from a request body. Available -starting with v2.6 -

-

REQUEST_COOKIES

-

This variable is a collection of all of request cookies (values -only). Example: the following example is using the Ampersand special -operator to count how many variables are in the collection. In this -rule, it would trigger if the request does not include any Cookie -headers. -

SecRule &REQUEST_COOKIES "@eq 0" "id:44" -

-

REQUEST_COOKIES_NAMES

-

This variable is a collection of the names of all request cookies. -For example, the following rule will trigger if the JSESSIONID cookie is - not present: -

SecRule &REQUEST_COOKIES_NAMES:JSESSIONID "@eq 0" -"id:45" -

-

REQUEST_FILENAME

-

This variable holds the relative request URL without the query string - part (e.g., /index.php). -

SecRule REQUEST_FILENAME "^/cgi-bin/login\.php$" -phase:2,id:46,t:none,t:normalizePath -

-
Note 
Please note that anti-evasion -transformations are not used on REQUEST_FILENAME, which means that you -will have to specify them in the rules that use this variable. -
-

REQUEST_HEADERS

-

This variable can be used as either a collection of all of the -request headers or can be used to inspect selected headers (by using the - REQUEST_HEADERS:Header-Name syntax). -

SecRule REQUEST_HEADERS:Host "^[\d\.]+$" -"deny,id:47,log,status:400,msg:'Host header is a numeric IP address'" -

-

REQUEST_HEADERS_NAMES

-

This variable is a collection of the names of all of the request -headers. -

SecRule REQUEST_HEADERS_NAMES "^x-forwarded-for" -"log,deny,id:48,status:403,t:lowercase,msg:'Proxy Server Used'" -

-

REQUEST_LINE

-

This variable holds the complete request line sent to the server -(including the request method and HTTP version information). -

-
# Allow only POST, GET and HEAD request methods, as well as only
-# the valid protocol versions 
-SecRule REQUEST_LINE "!(^((?:(?:POS|GE)T|HEAD))|HTTP/(0\.9|1\.0|1\.1)$)" "phase:1,id:49,log,block,t:none"
-
-

REQUEST_METHOD

-

This variable holds the request method used in the transaction. -

SecRule REQUEST_METHOD "^(?:CONNECT|TRACE)$" "id:50,t:none" -

-

REQUEST_PROTOCOL

-

This variable holds the request protocol version information. -

SecRule REQUEST_PROTOCOL "!^HTTP/(0\.9|1\.0|1\.1)$" "id:51" -

-

REQUEST_URI

-

This variable holds the full request URL including the query string -data (e.g., /index.php? p=X). However, it will never contain a domain -name, even if it was provided on the request line. -

SecRule REQUEST_URI "attack" -"phase:1,id:52,t:none,t:urlDecode,t:lowercase,t:normalizePath" -

-
Note 
Please note that anti-evasion -transformations are not used on REQUEST_URI, which means that you will -have to specify them in the rules that use this variable. -
-

REQUEST_URI_RAW

-

Same as REQUEST_URI but will contain the domain name if it was -provided on the request line (e.g., http://www.example.com/index.php?p=X). -

SecRule REQUEST_URI_RAW "http:/" -"phase:1,id:53,t:none,t:urlDecode,t:lowercase,t:normalizePath" -

-
Note 
Please note that anti-evasion -transformations are not used on REQUEST_URI_RAW, which means that you -will have to specify them in the rules that use this variable. -
-

RESPONSE_BODY

-

This variable holds the data for the response body, but only when -response body buffering is enabled. -

SecRule RESPONSE_BODY "ODBC Error Code" -"phase:4,id:54,t:none" -

-

RESPONSE_CONTENT_LENGTH

-

Response body length in bytes. Can be available starting with phase -3, but it does not have to be (as the length of response body is not -always known in advance). If the size is not known, this variable will -contain a zero. If RESPONSE_CONTENT_LENGTH contains a zero in phase 5 -that means the actual size of the response body was 0. The value of this - variable can change between phases if the body is modified. For -example, in embedded mode, mod_deflate can compress the response body -between phases 4 and 5. -

-

RESPONSE_CONTENT_TYPE

-

Response content type. Available only starting with phase 3. The -value available in this variable is taken directly from the internal -structures of Apache, which means that it may contain the information -that is not yet available in response headers. In embedded deployments, -you should always refer to this variable, rather than to -RESPONSE_HEADERS:Content-Type. -

-

RESPONSE_HEADERS

-

This variable refers to response headers, in the same way as -REQUEST_HEADERS does to request headers. -

SecRule RESPONSE_HEADERS:X-Cache "MISS" "id:55" -

This variable may not have access to some headers when running in - embedded mode. Headers such as Server, Date, Connection, and -Content-Type could be added just prior to sending the data to the -client. This data should be available in phase 5 or when deployed in -proxy mode. -

-

RESPONSE_HEADERS_NAMES

-

This variable is a collection of the response header names. -

SecRule RESPONSE_HEADERS_NAMES "Set-Cookie" -"phase:3,id:56,t:none" -

The same limitations apply as the ones discussed in -RESPONSE_HEADERS. -

-

RESPONSE_PROTOCOL

-

This variable holds the HTTP response protocol information. -

SecRule RESPONSE_PROTOCOL "^HTTP\/0\.9" -"phase:3,id:57,t:none" -

-

RESPONSE_STATUS

-

This variable holds the HTTP response status code: -

SecRule RESPONSE_STATUS "^[45]" "phase:3,id:58,t:none" -

This variable may not work as expected in embedded mode, as -Apache sometimes handles certain requests differently, and without -invoking ModSecurity (all other modules). -

-

RULE

-

This is a special collection that provides access to the id, rev, -severity, logdata, and msg fields of the rule that triggered the action. - It can be used to refer to only the same rule in which it resides. -

SecRule &REQUEST_HEADERS:Host "@eq 0" -"log,deny,id:59,setvar:tx.varname=%{RULE.id}" -

-

SCRIPT_BASENAME

-

This variable holds just the local filename part of SCRIPT_FILENAME. -

SecRule SCRIPT_BASENAME "^login\.php$" "id:60" -

-
Note 
Not available in proxy mode. -
-

SCRIPT_FILENAME

-

This variable holds the full internal path to the script that will be - used to serve the request. -

SecRule SCRIPT_FILENAME -"^/usr/local/apache/cgi-bin/login\.php$" "id:61" -

-
Note 
Not available in proxy mode. -
-

- SCRIPT_GID

-

This variable holds the numerical identifier of the group owner of -the script. -

SecRule SCRIPT_GID "!^46$" "id:62" -

-
Note 
Not available in proxy mode. -
-

SCRIPT_GROUPNAME

-

This variable holds the name of the group owner of the script. -

SecRule SCRIPT_GROUPNAME "!^apache$" "id:63" -

-
Note 
Not available in proxy mode. -
-

SCRIPT_MODE

-

This variable holds the script’s permissions mode data (e.g., 644). -

-
# Do not allow scripts that can be written to
-SecRule SCRIPT_MODE "^(2|3|6|7)$" "id:64"
-
-
Note 
Not available in proxy mode. -
-

- SCRIPT_UID

-

This variable holds the numerical identifier of the owner of the -script. -

-
# Do not run any scripts that are owned 
-# by Apache (Apache's user id is 46) 
-SecRule SCRIPT_UID "!^46$" "id:65"
-
-
Note 
Not available in proxy mode. -
-

SCRIPT_USERNAME

-

This variable holds the username of the owner of the script. -

-
# Do not run any scripts owned by Apache SecRule 
-SCRIPT_USERNAME "^apache$" "id:66"
-
-
Note 
Not available in proxy mode. -
-

SERVER_ADDR

-

This variable contains the IP address of the server. -

SecRule SERVER_ADDR "@ipMatch 192.168.1.100" "id:67" -

-

SERVER_NAME

-

This variable contains the transaction’s hostname or IP address, -taken from the request itself (which means that, in principle, it should - not be trusted). -

SecRule SERVER_NAME "hostname\.com$" "id:68" -

-

SERVER_PORT

-

This variable contains the local port that the web server (or reverse - proxy) is listening on. -

SecRule SERVER_PORT "^80$" "id:69" -

-

-SESSION

-

This variable is a collection that contains session information. It -becomes available only after setsid is executed. -

The following example shows how to initialize SESSION using -setsid, how to use setvar to increase the SESSION.score values, how to -set the SESSION.blocked variable, and finally, how to deny the -connection based on the SESSION:blocked value: -

-
# Initialize session storage 
-SecRule REQUEST_COOKIES:PHPSESSID !^$ "phase:2,id:70,nolog,pass,setsid:%{REQUEST_COOKIES.PHPSESSID}"
-
-# Increment session score on attack 
-SecRule REQUEST_URI "^/cgi-bin/finger$" "phase:2,id:71,t:none,t:lowercase,t:normalizePath,pass,setvar:SESSION.score=+10" 
-
-# Detect too many attacks in a session
-SecRule SESSION:score "@gt 50" "phase:2,id:72,pass,setvar:SESSION.blocked=1"
-
-# Enforce session block 
-SecRule SESSION:blocked "@eq 1" "phase:2,id:73,deny,status:403"
-
-

-SESSIONID

-

This variable contains the value set with setsid. See SESSION (above) - for a complete example. -

-

STREAM_INPUT_BODY

-

This variable give access to the raw request body content. This -variable is best used for two use-cases: -

-
  1. For fast pattern matching - using @pm/@pmf to prequalify large -text strings against any kind of content-type data. This is more -performant vs. using REQUEST_BODY/ARGS_POST/ARGS_POST_NAMES as it -happens before ModSecurity parsing in phase:2 variable population. -
  2. For data substitution - using @rsub against this variable -allows you to manipulate live request body data. Example - to remove -offending payloads or to substitute benign data. -
-
Note 
You must enable the -SecStreamInBodyInspection directive -
-

STREAM_OUTPUT_BODY

-

This variable give access to the raw response body content. This -variable is best used for case: -

-
  1. For data substitution - using @rsub against this variable allows - you to manipulate live request body data. Example - to remove -offending payloads or to substitute benign data. -
-
Note 
You must enable the -SecStreamOutBodyInspection directive -
-

TIME

-

This variable holds a formatted string representing the time -(hour:minute:second). -

SecRule TIME "^(([1](8|9))|([2](0|1|2|3))):\d{2}:\d{2}$" -"id:74" -

-

-TIME_DAY

-

This variable holds the current date (1–31). The following rule -triggers on a transaction that’s happening anytime between the 10th and -20th in a month: -

SecRule TIME_DAY "^(([1](0|1|2|3|4|5|6|7|8|9))|20)$" -"id:75" -

-

- TIME_EPOCH

-

This variable holds the time in seconds since 1970. -

-

-TIME_HOUR

-

This variable holds the current hour value (0–23). The following rule - triggers when a request is made “off hours”: -

SecRule TIME_HOUR "^(0|1|2|3|4|5|6|[1](8|9)|[2](0|1|2|3))$" - "id:76" -

-

-TIME_MIN

-

This variable holds the current minute value (0–59). The following -rule triggers during the last half hour of every hour: -

SecRule TIME_MIN "^(3|4|5)" "id:77" -

-

-TIME_MON

-

This variable holds the current month value (0–11). The following -rule matches if the month is either November (value 10) or December -(value 11): -

SecRule TIME_MON "^1" "id:78" -

-

-TIME_SEC

-

This variable holds the current second value (0–59). -

SecRule TIME_SEC "@gt 30" "id:79" -

-

-TIME_WDAY

-

This variable holds the current weekday value (0–6). The following -rule triggers only on Satur- day and Sunday: -

SecRule TIME_WDAY "^(0|6)$" "id:80" -

-

-TIME_YEAR

-

This variable holds the current four-digit year value. -

SecRule TIME_YEAR "^2006$" "id:81" -

-

TX

-

This is the transient transaction collection, which is used to store -pieces of data, create a transaction anomaly score, and so on. The -variables placed into this collection are available only until the -transaction is complete. -

-
# Increment transaction attack score on attack 
-SecRule ARGS attack "phase:2,id:82,nolog,pass,setvar:TX.score=+5"
-
-# Block the transactions whose scores are too high 
-SecRule TX:SCORE "@gt 20" "phase:2,id:83,log,deny"
-
-

Some variable names in the TX collection are reserved and cannot be -used: -

-
  • TX:0: the matching value when using the @rx or @pm operator with - the capture action -
  • TX:1-TX:9: the captured subexpression value when using the @rx -operator with capturing parens and the capture action -
  • TX:MSC_.*: ModSecurity processing flags -
  • MSC_PCRE_LIMITS_EXCEEDED: Set to nonzero if PCRE match limits -are exceeded. See SecPcreMatchLimit and SecPcreMatchLimitRecursion for -more information. -
-

-UNIQUE_ID

-

This variable holds the data created by mod_unique_id [7]. This module provides a magic token for each -request which is guaranteed to be unique across "all" requests under -very specific conditions. The unique identifier is even unique across -multiple machines in a properly configured cluster of machines. The -environment variable UNIQUE_ID is set to the identifier for each -request. The UNIQUE_ID environment variable is constructed by encoding -the 112-bit (32-bit IP address, 32 bit pid, 32 bit time stamp, 16 bit -counter) quadruple using the alphabet [A-Za-z0-9@-] in a manner similar -to MIME base64 encoding, producing 19 characters. -

-

URLENCODED_ERROR

-

This variable is created when an invalid URL encoding is encountered -during the parsing of a query string (on every request) or during the -parsing of an application/x-www-form-urlencoded request body (only on -the requests that use the URLENCODED request body processor). -

-

USERID

-

This variable contains the value set with setuid. -

-
# Initialize user tracking
-SecAction "nolog,id:84,pass,setuid:%{REMOTE_USER}" 
-
-# Is the current user the administrator?
-SecRule USERID "admin" "id:85"
-
-

USERAGENT_IP

-

This variable is created when running modsecurity with apache2.4 and -will contains the client ip address set by mod_remoteip in proxied -connections. -

-

-WEBAPPID

-

This variable contains the current application name, which is set in -configuration using SecWebAppId. -

-

WEBSERVER_ERROR_LOG

-

Contains zero or more error messages produced by the web server. This - variable is best accessed from phase 5 (logging). -

SecRule WEBSERVER_ERROR_LOG "File does not exist" -"phase:5,id:86,t:none,nolog,pass,setvar:TX.score=+5" -

-

XML

-

Special collection used to interact with the XML parser. It can be -used standalone as a target for the validateDTD and validateSchema -operator. Otherwise, it must contain a valid XPath expression, which -will then be evaluated against a previously parsed XML DOM tree. -

-
SecDefaultAction log,deny,status:403,phase:2,id:90
-SecRule REQUEST_HEADERS:Content-Type ^text/xml$ "phase:1,id:87,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML"
-SecRule REQBODY_PROCESSOR "!^XML$" skipAfter:12345,id:88
-
-SecRule XML:/employees/employee/name/text() Fred "id:89"
-SecRule XML:/xq:employees/employee/name/text() Fred "id:12345,xmlns:xq=http://www.example.com/employees"
-
-

The first XPath expression does not use namespaces. It would match -against payload such as this one: -

-
<employees>
-    <employee>
-        <name>Fred Jones</name>
-        <address location="home">
-            <street>900 Aurora Ave.</street>
-            <city>Seattle</city>
-            <state>WA</state>
-            <zip>98115</zip>
-        </address>
-        <address location="work">
-            <street>2011 152nd Avenue NE</street>
-            <city>Redmond</city>
-            <state>WA</state>
-            <zip>98052</zip>
-        </address>
-        <phone location="work">(425)555-5665</phone>
-        <phone location="home">(206)555-5555</phone>
-        <phone location="mobile">(206)555-4321</phone>
-    </employee>
-</employees>
-
-

The second XPath expression does use namespaces. It would match the -following payload: -

-
<xq:employees xmlns:xq="http://www.example.com/employees">
-    <employee>
-        <name>Fred Jones</name>
-        <address location="home">
-            <street>900 Aurora Ave.</street>
-            <city>Seattle</city>
-            <state>WA</state>
-            <zip>98115</zip>
-        </address>
-        <address location="work">
-            <street>2011 152nd Avenue NE</street>
-            <city>Redmond</city>
-            <state>WA</state>
-            <zip>98052</zip>
-        </address>
-        <phone location="work">(425)555-5665</phone>
-        <phone location="home">(206)555-5555</phone>
-        <phone location="mobile">(206)555-4321</phone>
-    </employee>
-</xq:employees>
-
-

Note the different namespace used in the second example. -

-

- Transformation functions

-

Transformation functions are used to alter input data before it is -used in matching (i.e., operator execution). The input data is never -modified, actually—whenever you request a transformation function to be -used, ModSecurity will create a copy of the data, transform it, and then - run the operator against the result. -

-
Note 
There are no default transformation -functions, as there were in the first generation of ModSecurity (1.x). -
-

In the following example, the request parameter values are converted -to lowercase before matching: -

SecRule ARGS "xp_cmdshell" "t:lowercase,id:91" -

Multiple transformation actions can be used in the same rule, -forming a transformation pipeline. The transformations will be performed - in the order in which they appear in the rule. -

In most cases, the order in which transformations are performed -is very important. In the following example, a series of transformation -functions is performed to counter evasion. Performing the -transformations in any other order would allow a skillful attacker to -evade detection: -

SecRule ARGS -"(asfunction|javascript|vbscript|data|mocha|livescript):" -"id:92,t:none,t:htmlEntityDecode,t:lowercase,t:removeNulls,t:removeWhitespace" -

-
Warning 
It is currently possible to use -SecDefaultAction to specify a default list of transformation functions, -which will be applied to all rules that follow the SecDefaultAction -directive. However, this practice is not recommended, because it means -that mistakes are very easy to make. It is recommended that you always -specify the transformation functions that are needed by a particular -rule, starting the list with t:none (which clears the possibly inherited - transformation functions). -
-

The remainder of this section documents the transformation functions -currently available in ModSecurity. -

-

base64Decode

-

Decodes a Base64-encoded string. -

-
SecRule REQUEST_HEADERS:Authorization "^Basic ([a-zA-Z0-9]+=*)$" "phase:1,id:93,capture,chain,logdata:%{TX.1}"
-  SecRule TX:1 ^(\w+): t:base64Decode,capture,chain
-    SecRule TX:1 ^(admin|root|backup)$ 
-
-

sqlHexDecode

-

Decode sql hex data. Example (0x414243) will be decoded to (ABC). -Available as of 2.6.3 -

-

base64DecodeExt

-

Decodes a Base64-encoded string. Unlike base64Decode, this version -uses a forgiving implementation, which ignores invalid characters. -Available as of 2.5.13. -

See blog post on Base64Decoding evasion issues on PHP sites - http://blog.spiderlabs.com/2010/04/impedance-mismatch-and-base64.html -

-

base64Encode

-

Encodes input string using Base64 encoding. -

-

-cmdLine

-
Note 
This is a community contribution developed -by Marc Stern [8] -
-

In Windows and Unix, commands may be escaped by different means, such - as: -

-
  • c^ommand /c ... -
  • "command" /c ... -
  • command,/c ... -
  • backslash in the middle of a Unix command -
-

The cmdLine transformation function avoids this problem by -manipulating the variable contend in the following ways: -

-
  • deleting all backslashes [\] -
  • deleting all double quotes ["] -
  • deleting all sigle quotes ['] -
  • deleting all carets [^] -
  • deleting spaces before a slash [/] -
  • deleting spaces before an open parentesis [(] -
  • replacing all commas [,] and semicolon [;] into a space -
  • replacing all multiple spaces (including tab, newline, etc.) -into one space -
  • transform all characters to lowercase -
-

Example Usage: -

-
SecRule ARGS "(?:command(?:.com)?|cmd(?:.exe)?)(?:/.*)?/[ck]" "phase:2,id:94,t:none, t:cmdLine"
-
-

compressWhitespace

-

Converts any of the whitespace characters (0x20, \f, \t, \n, \r, \v, -0xa0) to spaces (ASCII 0x20), compressing multiple consecutive space -characters into one. -

-

-cssDecode

-

Decodes characters encoded using the CSS 2.x escape rules syndata.html#characters. - This function uses only up to two bytes in the decoding process, -meaning that it is useful to uncover ASCII characters encoded using CSS -encoding (that wouldn’t normally be encoded), or to counter evasion, -which is a combination of a backslash and non-hexadecimal characters -(e.g., ja\vascript is equivalent to javascript). -

-

escapeSeqDecode

-

Decodes ANSI C escape sequences: \a, \b, \f, \n, \r, \t, \v, \\, \?, -\', \", \xHH (hexadecimal), \0OOO (octal). Invalid encodings are left in - the output. -

-

-hexDecode

-

Decodes a string that has been encoded using the same algorithm as -the one used in hexEncode (see following entry). -

-

-hexEncode

-

Encodes string (possibly containing binary characters) by replacing -each input byte with two hexadecimal characters. For example, xyz is -encoded as 78797a. -

-

htmlEntityDecode

-

Decodes the characters encoded as HTML entities. The following -variants are supported: -

-
  • &#xHH and &#xHH; (where H is any hexadecimal number) -
  • &#DDD and &#DDD; (where D is any decimal number) -
  • &quotand" -
  • &nbspand  -
  • &ltand< -
  • &gtand> -
-

This function always converts one HTML entity into one byte, possibly - resulting in a loss of information (if the entity refers to a character - that cannot be represented with the single byte). It is thus useful to -uncover bytes that would otherwise not need to be encoded, but it cannot - do anything meaningful with the characters from the range above 0xff. -

-

-jsDecode

-

Decodes JavaScript escape sequences. If a \uHHHH code is in the range - of FF01-FF5E (the full width ASCII codes), then the higher byte is used - to detect and adjust the lower byte. Otherwise, only the lower byte -will be used and the higher byte zeroed (leading to possible loss of -information). -

-

length

-

Looks up the length of the input string in bytes, placing it (as -string) in output. For example, if it gets ABCDE on input, this -transformation function will return 5 on output. -

-

-lowercase

-

Converts all characters to lowercase using the current C locale. -

-

md5

-

Calculates an MD5 hash from the data in input. The computed hash is -in a raw binary form and may need encoded into text to be printed (or -logged). Hash functions are commonly used in combination with hexEncode -(for example: t:md5,t:hexEncode). -

-

none

-

Not an actual transformation function, but an instruction to -ModSecurity to remove all transformation functions associated with the -current rule. -

-

normalisePath

-

Removes multiple slashes, directory self-references, and directory -back-references (except when at the beginning of the input) from input -string. -

-

normalisePathWin

-

Same as normalisePath, but first converts backslash characters to -forward slashes. -

-

parityEven7bit

-

Calculates even parity of 7-bit data replacing the 8th bit of each -target byte with the calculated parity bit. -

-

parityOdd7bit

-

Calculates odd parity of 7-bit data replacing the 8th bit of each -target byte with the calculated parity bit. -

-

parityZero7bit

-

Calculates zero parity of 7-bit data replacing the 8th bit of each -target byte with a zero-parity bit, which allows inspection of even/odd -parity 7-bit data as ASCII7 data. -

-

removeNulls

-

Removes all NUL bytes from input. -

-

removeWhitespace

-

Removes all whitespace characters from input. -

-

replaceComments

-

Replaces each occurrence of a C-style comment (/* ... */) with a -single space (multiple consecutive occurrences of which will not be -compressed). Unterminated comments will also be replaced with a space -(ASCII 0x20). However, a standalone termination of a comment (*/) will -not be acted upon. -

-

removeCommentsChar

-

Removes common comments chars (/*, */, --, #). -

-

removeComments

-

Removes each occurrence of comment (/* ... */, --, #). Multiple -consecutive occurrences of which will not be compressed. -

-

replaceNulls

-

Replaces NUL bytes in input with space characters (ASCII 0x20). -

-

-urlDecode

-

Decodes a URL-encoded input string. Invalid encodings (i.e., the ones - that use non-hexadecimal characters, or the ones that are at the end of - string and have one or two bytes missing) are not converted, but no -error is raised. To detect invalid encodings, use the -@validateUrlEncoding operator on the input data first. The -transformation function should not be used against variables that have -already been URL-decoded (such as request parameters) unless it is your -intention to perform URL decoding twice! -

-

urlDecodeUni

-

Like urlDecode, but with support for the Microsoft-specific %u -encoding. If the code is in the range of FF01-FF5E (the full-width ASCII - codes), then the higher byte is used to detect and adjust the lower -byte. Otherwise, only the lower byte will be used and the higher byte -zeroed. -

-

-urlEncode

-

Encodes input string using URL encoding. -

-

utf8toUnicode

-

Converts all UTF-8 characters sequences to Unicode. This help input -normalization specially for non-english languages minimizing -false-positives and false-negatives. (available with 2.7.0) -

-

sha1

-

Calculates a SHA1 hash from the input string. The computed hash is in - a raw binary form and may need encoded into text to be printed (or -logged). Hash functions are commonly used in combination with hexEncode -(for example, t:sha1,t:hexEncode). -

-

-trimLeft

-

Removes whitespace from the left side of the input string. -

-

-trimRight

-

Removes whitespace from the right side of the input string. -

-

trim

-

Removes whitespace from both the left and right sides of the input -string. -

-

-Actions

-

Each action belongs to one of five groups: -

-
  • Disruptive actions - Cause ModSecurity to do something. -In many cases something means block transaction, but not in all. For -example, the allow action is classified as a disruptive action, but it -does the opposite of blocking. There can only be one disruptive action -per rule (if there are multiple disruptive actions present, or -inherited, only the last one will take effect), or rule chain (in a -chain, a disruptive action can only appear in the first rule). -
-
Note 
Disruptive actions will NOT be executed -if the SecRuleEngine is set to DetectionOnly. If you are creating -exception/whitelisting rules that use the allow action, you should also -add the ctl:ruleEngine=On action to execute the action. -
-
  • Non-disruptive actions - Do something, but that -something does not and cannot affect the rule processing flow. Setting a - variable, or changing its value is an example of a non-disruptive -action. Non-disruptive action can appear in any rule, including each -rule belonging to a chain. -
  • Flow actions - These actions affect the rule flow (for -example skip or skipAfter). -
  • Meta-data actions - Meta-data actions are used to -provide more information about rules. Examples include id, rev, severity - and msg. -
  • Data actions - Not really actions, these are mere -containers that hold data used by other actions. For example, the status - action holds the status that will be used for blocking (if it takes -place). -
-

-accuracy

-

Description: Specifies the relative accuracy level of the rule - related to false positives/negatives. The value is a string based on a - numeric scale (1-9 where 9 is very strong and 1 has many false -positives). -

Action Group: Meta-data -

Version: 2.7 -

Example: -

-
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "\bgetparentfolder\b" \
-	"phase:2,ver:'CRS/2.2.4,accuracy:'9',maturity:'9',capture,t:none,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,msg:'Cross-site Scripting (XSS) Attack',id:'958016',tag:'WEB_ATTACK/XSS',tag:'WASCTC/WASC-8',tag:'WASCTC/WASC-22',tag:'OWASP_TOP_10/A2',tag:'OWASP_AppSensor/IE1',tag:'PCI/6.5.1',logdata:'% \
-{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+%{tx.critical_anomaly_score},setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{tx.0}"
-
-

allow

-

Description: Stops rule processing on a successful match and -allows the transaction to proceed. -

Action Group: Disruptive -

Example: -

-
# Allow unrestricted access from 192.168.1.100 
-SecRule REMOTE_ADDR "^192\.168\.1\.100$" phase:1,id:95,nolog,allow
-
-


-Prior to ModSecurity 2.5 the allow action would only affect the current -phase. An allow in phase 1 would skip processing the remaining rules in -phase 1 but the rules from phase 2 would execute. Starting with v2.5.0 -allow was enhanced to allow for fine-grained control of what is done. -The following rules now apply: -

-
  1. If used one its own, like in the example above, allow will -affect the entire transaction, stopping processing of the current phase -but also skipping over all other phases apart from the logging phase. -(The logging phase is special; it is designed to always execute.) -
  2. If used with parameter "phase", allow will cause the engine to -stop processing the current phase. Other phases will continue as normal. -
  3. If used with parameter "request", allow will cause the engine -to stop processing the current phase. The next phase to be processed -will be phase RESPONSE_HEADERS. -
-

Examples: -

-
# Do not process request but process response.
-SecAction phase:1,allow:request,id:96
-
-# Do not process transaction (request and response).
-SecAction phase:1,allow,id:97
-
-

If you want to allow a response through, put a rule in phase -RESPONSE_HEADERS and simply use allow on its own: -

-
# Allow response through.
-SecAction phase:3,allow,id:98
-
-

append

-

Description: Appends text given as parameter to the end of -response body. Content injection must be en- abled (using the -SecContentInjection directive). No content type checks are made, which -means that before using any of the content injection actions, you must -check whether the content type of the response is adequate for -injection. -

Action Group: Non-disruptive -

Processing Phases: 3 and 4. -

Example: -

-
SecRule RESPONSE_CONTENT_TYPE "^text/html" "nolog,id:99,pass,append:'<hr>Footer'"
-
Warning 
Although macro expansion is allowed in -the additional content, you are strongly cau- tioned against inserting -user-defined data fields into output. Doing so would create a cross-site - scripting vulnerability. -
-

-auditlog

-

Description: Marks the transaction for logging in the audit -log. -

Action Group: Non-disruptive -

Example: -

SecRule REMOTE_ADDR "^192\.168\.1\.100$" -auditlog,phase:1,id:100,allow -

-
Note 
The auditlog action is now explicit if log -is already specified. -
-

block

-

Description: Performs the disruptive action defined by the -previous SecDefaultAction. -

Action Group: Disruptive -

This action is essentially a placeholder that is intended to be -used by rule writers to request a blocking action, but without -specifying how the blocking is to be done. The idea is that such -decisions are best left to rule users, as well as to allow users, to -override blocking if they so desire. -In future versions of ModSecurity, more control and functionality will -be added to define "how" to block. -

Examples: -

-
# Specify how blocking is to be done 
-SecDefaultAction phase:2,deny,id:101,status:403,log,auditlog
-
-# Detect attacks where we want to block 
-SecRule ARGS attack1 phase:2,block,id:102
-
-# Detect attacks where we want only to warn 
-SecRule ARGS attack2 phase:2,pass,id:103
-
-

It is possible to use the SecRuleUpdateActionById directive to -override how a rule handles blocking. This is useful in three cases: -

-
  1. If a rule has blocking hard-coded, and you want it to use the -policy you determine -
  2. If a rule was written to block, but you want it to only warn -
  3. If a rule was written to only warn, but you want it to block -
-

The following example demonstrates the first case, in which the -hard-coded block is removed in favor of the user-controllable block: -

-
# Specify how blocking is to be done 
-SecDefaultAction phase:2,deny,status:403,log,auditlog,id:104
-
-# Detect attacks and block 
-SecRule ARGS attack1 phase:2,id:1,deny
-
-# Change how rule ID 1 blocks 
-SecRuleUpdateActionById 1 block
-
-

-capture

-

Description: When used together with the regular expression -operator (@rx), the capture action will create copies of the regular -expression captures and place them into the transaction variable -collection. -

Action Group: Non-disruptive -

Example: -

-
SecRule REQUEST_BODY "^username=(\w{25,})" phase:2,capture,t:none,chain,id:105
-  SecRule TX:1 "(?:(?:a(dmin|nonymous)))"
-
-

Up to 10 captures will be copied on a successful pattern match, each -with a name consisting of a digit from 0 to 9. The TX.0 variable always -contains the entire area that the regular expression matched. All the -other variables contain the captured values, in the order in which the -capturing parentheses appear in the regular expression. -

-

chain

-

Description: Chains the current rule with the rule that -immediately follows it, creating a rule chain. Chained rules allow for -more complex processing logic. -

Action Group: Flow -

Example: -

-
# Refuse to accept POST requests that do not contain Content-Length header. 
-# (Do note that this rule should be preceded by a rule 
-# that verifies only valid request methods are used.) 
-SecRule REQUEST_METHOD "^POST$" phase:1,chain,t:none,id:105
-  SecRule &REQUEST_HEADERS:Content-Length "@eq 0" t:none
-
-
Note 
Rule chains allow you to simulate logical -AND. The disruptive actions specified in the first portion of the -chained rule will be triggered only if all of the variable checks return - positive hits. If any one aspect of a chained rule comes back negative, - then the entire rule chain will fail to match. Also note that -disruptive actions, execution phases, metadata actions (id, rev, msg, -tag, severity, logdata), skip, and skipAfter actions can be specified -only by the chain starter rule. -
-

The following directives can be used in rule chains: -

-
  • SecAction -
  • SecRule -
  • SecRuleScript -
-

Special rules control the usage of actions in chained rules: -

-
  • Any actions that affect the rule flow (i.e., the disruptive -actions, skip and skipAfter) can be used only in the chain starter. They - will be executed only if the entire chain matches. -
  • Non-disruptive rules can be used in any rule; they will be -executed if the rule that contains them matches and not only when the -entire chain matches. -
  • The metadata actions (e.g., id, rev, msg) can be used only in -the chain starter. -
-

ctl

-

Description: Changes ModSecurity configuration on transient, -per-transaction basis. Any changes made using this action will affect -only the transaction in which the action is executed. The default -configuration, as well as the other transactions running in parallel, -will be unaffected. -

Action Group: Non-disruptive -

Example: -

-
# Parse requests with Content-Type "text/xml" as XML 
-SecRule REQUEST_CONTENT_TYPE ^text/xml "nolog,pass,id:106,ctl:requestBodyProcessor=XML"
-
-

The following configuration options are supported: -

-
  1. auditEngine -
  2. auditLogParts -
  3. debugLogLevel -
  4. forceRequestBodyVariable -
  5. requestBodyAccess -
  6. requestBodyLimit -
  7. requestBodyProcessor -
  8. responseBodyAccess -
  9. responseBodyLimit -
  10. ruleEngine -
  11. ruleRemoveById - since this action us triggered at run -time, it should be specified before the rule in which it is -disabling. -
  12. ruleUpdateTargetById - This is deprecated and will be -removed from the code. Use ruleRemoveTargetById for per-request -exceptions. -
  13. ruleRemoveTargetById - since this action is used to just - remove targets, users don't need to use the char ! before the -target list. -
  14. ruleRemoveByMsg -
  15. encryptionEngine -
  16. encryptionEnforcement -
-

With the exception of the requestBodyProcessor and -forceRequestBodyVariable settings, each configuration option corresponds - to one configuration directive and the usage is identical. -

The requestBodyProcessor option allows you to configure the -request body processor. By default, ModSecurity will use the URLENCODED -and MULTIPART processors to process an application/x-www-form-urlencoded - and a multipart/form-data body, respectively. A third processor, XML, -is also supported, but it is never used implicitly. Instead, you must -tell ModSecurity to use it by placing a few rules in the REQUEST_HEADERS - processing phase. After the request body is processed as XML, you will -be able to use the XML-related features to inspect it. -

Request body processors will not interrupt a transaction if an -error occurs during parsing. Instead, they will set the variables -REQBODY_PROCESSOR_ERROR and REQBODY_PROCESSOR_ERROR_MSG. These variables - should be inspected in the REQUEST_BODY phase and an appropriate action - taken. -The forceRequestBodyVariable option allows you to configure the -REQUEST_BODY variable to be set when there is no request body processor -configured. This allows for inspection of request bodies of unknown -types. -

-

deny

-

Description: Stops rule processing and intercepts transaction. -

Action Group: Disruptive -

Example: -SecRule REQUEST_HEADERS:User-Agent "nikto" -"log,deny,id:107,msg:'Nikto Scanners Identified'" -

-

deprecatevar

-

Description: Decrements numerical value over time, which makes - sense only applied to the variables stored in persistent storage. -

Action Group: Non-Disruptive -

Example: The following example will decrement the counter by 60 -every 300 seconds. -

-
SecAction phase:5,id:108,nolog,pass,deprecatevar:SESSION.score=60/300
-
-

Counter values are always positive, meaning that the value will never - go below zero. Unlike expirevar, the deprecate action must be executed -on every request. -

-

drop

-

Description: Initiates an immediate close of the TCP -connection by sending a FIN packet. -

Action Group: Disruptive -

Example: The following example initiates an IP collection -for tracking Basic Authentication attempts. If the client goes over the -threshold of more than 25 attempts in 2 minutes, it will DROP subsequent - connections. -

-
SecAction phase:1,id:109,initcol:ip=%{REMOTE_ADDR},nolog
-SecRule ARGS:login "!^$" "nolog,phase:1,id:110,setvar:ip.auth_attempt=+1,deprecatevar:ip.auth_attempt=20/120"
-SecRule IP:AUTH_ATTEMPT "@gt 25" "log,drop,phase:1,id:111,msg:'Possible Brute Force Attack'"
-
-
Note 
This action is currently not available on -Windows based builds. -
-

This action is extremely useful when responding to both Brute Force -and Denial of Service attacks in that, in both cases, you want to -minimize both the network bandwidth and the data returned to the client. - This action causes error message to appear in the log "(9)Bad file -descriptor: core_output_filter: writing data to the network" -

-

exec

-

Description: Executes an external script/binary supplied as -parameter. As of v2.5.0, if the parameter supplied to exec is a Lua -script (detected by the .lua extension) the script will be processed -internally. This means you will get direct access to the internal -request context from the script. Please read the SecRuleScript -documentation for more details on how to write Lua scripts. -

Action Group: Non-disruptive -

Example: -

-
# Run external program on rule match 
-SecRule REQUEST_URI "^/cgi-bin/script\.pl" "phase:2,id:112,t:none,t:lowercase,t:normalizePath,block,\ exec:/usr/local/apache/bin/test.sh"
-
-# Run Lua script on rule match 
-SecRule ARGS:p attack "phase:2,id:113,block,exec:/usr/local/apache/conf/exec.lua"
-
-

The exec action is executed independently from any disruptive actions - specified. External scripts will always be called with no parameters. -Some transaction information will be placed in environment variables. -All the usual CGI environment variables will be there. You should be -aware that forking a threaded process results in all threads being -replicated in the new process. Forking can therefore incur larger -overhead in a multithreaded deployment. The script you execute must -write something (anything) to stdout; if it doesn’t, ModSecurity will -assume that the script failed, and will record the failure. -

-

-expirevar

-

Description: Configures a collection variable to expire after -the given time period (in seconds). -

Action Group: Non-disruptive -

Example: -

-
SecRule REQUEST_COOKIES:JSESSIONID "!^$" "nolog,phase:1,id:114,pass,setsid:%{REQUEST_COOKIES:JSESSIONID}"
-SecRule REQUEST_URI "^/cgi-bin/script\.pl" "phase:2,id:115,t:none,t:lowercase,t:normalisePath,log,allow,setvar:session.suspicious=1,expirevar:session.suspicious=3600,phase:1"
-
-

You should use the expirevar actions at the same time that you use -setvar actions in order to keep the indented expiration time. If they -are used on their own (perhaps in a SecAction directive), the expire -time will be reset. -

-

id

-

Description: Assigns a unique ID to the rule or chain in which - it appears. Starting with ModSecurity 2.7 this action is mandatory and -must be numeric. -

Action Group: Meta-data -

Example: -

-
SecRule &REQUEST_HEADERS:Host "@eq 0" "log,id:60008,severity:2,msg:'Request Missing a Host Header'"
-
-

These are the reserved ranges: -

-
  • 1–99,999: reserved for local (internal) use. Use as you see fit, - but do not use this range for rules that are distributed to others -
  • 100,000–199,999: reserved for internal use of the engine, to -assign to rules that do not have explicit IDs -
  • 200,000–299,999: reserved for rules published at -modsecurity.org -
  • 300,000–399,999: reserved for rules published at gotroot.com -
  • 400,000–419,999: unused (available for reservation) -
  • 420,000–429,999: reserved for ScallyWhack [9] -
  • 430,000–439,999: reserved for rules published by Flameeyes [10] -
  • 440.000-599,999: unused (available for reservation) -
  • 600,000-699,999: reserved for use by Akamai [11] -
  • 700,000–799,999: reserved for Ivan Ristic -
  • 900,000–999,999: reserved for the OWASP ModSecurity Core Rule -Set [12] project -
  • 1,000,000-1,999,999: unused (available for reservation) -
  • 2,000,000-2,999,999: reserved for rules from Trustwave's -SpiderLabs Research team -
  • 3,000,000 and above: unused (available for reservation) -
-

-initcol

-

Description: Initializes a named persistent collection, either - by loading data from storage or by creating a new collection in memory. -

Action Group: Non-disruptive -

Example: The following example initiates IP address -tracking, which is best done in phase 1: -

-
SecAction phase:1,id:116,nolog,pass,initcol:ip=%{REMOTE_ADDR}
-
-

Collections are loaded into memory on-demand, when the initcol action - is executed. A collection will be persisted only if a change was made -to it in the course of transaction processing. -

See the "Persistant Storage" section for further details. -

-

log

-

Description: Indicates that a successful match of the rule -needs to be logged. -

Action Group: Non-disruptive -

Example: -

-
SecAction phase:1,id:117,pass,initcol:ip=%{REMOTE_ADDR},log
-
-

This action will log matches to the Apache error log file and the -ModSecurity audit log. -

-

-logdata

-

Description: Logs a data fragment as part of the alert -message. -

Action Group: Non-disruptive -

Example: -

-
SecRule ARGS:p "@rx <script>" "phase:2,id:118,log,pass,logdata:%{MATCHED_VAR}"
-
-

The logdata information appears in the error and/or audit log files. -Macro expansion is performed, so you may use variable names such -as %{TX.0} or %{MATCHED_VAR}. The information is properly -escaped for use with logging of binary data. -

-

-maturity

-

Description: Specifies the relative maturity level of the rule - related to the length of time a rule has been public and the amount of -testing it has received. The value is a string based on a numeric scale - (1-9 where 9 is extensively tested and 1 is a brand new experimental -rule). -

Action Group: Meta-data -

Version: 2.7 -

Example: -

-
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "\bgetparentfolder\b" \
-	"phase:2,ver:'CRS/2.2.4,accuracy:'9',maturity:'9',capture,t:none,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,msg:'Cross-site Scripting (XSS) Attack',id:'958016',tag:'WEB_ATTACK/XSS',tag:'WASCTC/WASC-8',tag:'WASCTC/WASC-22',tag:'OWASP_TOP_10/A2',tag:'OWASP_AppSensor/IE1',tag:'PCI/6.5.1',logdata:'% \
-{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+%{tx.critical_anomaly_score},setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{tx.0}"
-
-

msg

-

Description: Assigns a custom message to the rule or chain in -which it appears. The message will be logged along with every alert. -

Action Group: Meta-data -

Example: -

-
SecRule &REQUEST_HEADERS:Host "@eq 0" "log,id:60008,severity:2,msg:'Request Missing a Host Header'"
-
-
Note 
The msg information appears in the error -and/or audit log files and is not sent back to the client in response -headers. -
-

- multiMatch

-

Description: If enabled, ModSecurity will perform multiple -operator invocations for every target, before and after every -anti-evasion transformation is performed. -

Action Group: Non-disruptive -

Example: -

-
SecRule ARGS "attack" "phase1,log,deny,id:119,t:removeNulls,t:lowercase,multiMatch"
-
-

Normally, variables are inspected only once per rule, and only after -all transformation functions have been completed. With multiMatch, -variables are checked against the operator before and after every -transformation function that changes the input. -

-

- noauditlog

-

Description: Indicates that a successful match of the rule -should not be used as criteria to determine whether the transaction -should be logged to the audit log. -

Action Group: Non-disruptive -

Example: -

-
SecRule REQUEST_HEADERS:User-Agent "Test" allow,noauditlog,id:120
-
-

If the SecAuditEngine is set to On, all of the transactions will be -logged. If it is set to RelevantOnly, then you can control the logging -with the noauditlog action. -

The noauditlog action affects only the current rule. If you -prevent audit logging in one rule only, a match in another rule will -still cause audit logging to take place. If you want to prevent audit -logging from taking place, regardless of whether any rule matches, use -ctl:auditEngine=Off. -

-

nolog

-

Description: Prevents rule matches from appearing in both the -error and audit logs. -

Action Group: Non-disruptive -

Example: -

-
SecRule REQUEST_HEADERS:User-Agent "Test" allow,nolog,id:121
-
-

Although nolog implies noauditlog, you can override the former by -using nolog,auditlog. -

-

pass

-

Description: Continues processing with the next rule in spite -of a successful match. -

Action Group: Disruptive -

Example: -

-
SecRule REQUEST_HEADERS:User-Agent "Test" "log,pass,id:122"
-
-

When using pass with a SecRule with multiple targets, all variables -will be inspected and all non-disruptive actions trigger for every -match. In the following example, the TX.test variable will be -incremented once for every request parameter: -

-
# Set TX.test to zero 
-SecAction "phase:2,nolog,pass,setvar:TX.test=0,id:123"
-
-# Increment TX.test for every request parameter 
-SecRule ARGS "test" "phase:2,log,pass,setvar:TX.test=+1,id:124"
-
-

pause

-

Description: Pauses transaction processing for the specified -number of milliseconds. Starting with ModSecurity 2.7 this feature also -supports macro expansion. -

Action Group: Disruptive -

Example: -

-
SecRule REQUEST_HEADERS:User-Agent "Test" "log,pause:5000,id:125"
-
-
Warning 
This feature can be of limited benefit -for slowing down brute force authentication attacks, but use with care. -If you are under a denial of service attack, the pause feature may make -matters worse, as it will cause an entire Apache worker (process or -thread, depending on the deployment mode) to sit idle until the pause is - completed. -
-

phase

-

Description: Places the rule or chain into one of five -available processing phases. It can also be used in SecDefaultAction to -establish the rule defaults. -

Action Group: Meta-data -

Example: -

-
# Initialize IP address tracking in phase 1
-SecAction phase:1,nolog,pass,id:126,initcol:IP=%{REMOTE_ADDR}
-
-

Starting in ModSecurity version v2.7 there are aliases for some phase - numbers: -

-
  • 2 - request -
  • 4 - response -
  • 5 - logging -
-

Example: -

-
SecRule REQUEST_HEADERS:User-Agent "Test" "phase:request,log,deny,id:127"
-
-
Warning 
Keep in mind that if you specify the -incorrect phase, the variable used in the rule may not yet be available. - This could lead to a false negative situation where your variable and -operator may be correct, but it misses malicious data because you -specified the wrong phase. -
-

-prepend

-

Description: Prepends the text given as parameter to response -body. Content injection must be enabled (using the SecContentInjection -directive). No content type checks are made, which means that before -using any of the content injection actions, you must check whether the -content type of the response is adequate for injection. -

Action Group: Non-disruptive -

Processing Phases: 3 and 4. -

Example: -

-
SecRule RESPONSE_CONTENT_TYPE ^text/html \ "phase:3,nolog,pass,id:128,prepend:'Header<br>'"
-
-
Warning 
Although macro expansion is allowed in -the injected content, you are strongly cautioned against inserting user -defined data fields int output. Doing so would create a cross-site -scripting vulnerability. -
-

proxy

-

Description: Intercepts the current transaction by forwarding -the request to another web server using the proxy backend. The -forwarding is carried out transparently to the HTTP client (i.e., -there’s no external redirection taking place). -

Action Group: Disruptive -

Example: -

-
SecRule REQUEST_HEADERS:User-Agent "Test" log,id:129,proxy:http://honeypothost/
-
-

For this action to work, mod_proxy must also be installed. This -action is useful if you would like to proxy matching requests onto a -honeypot web server, and especially in combination with IP address or -session tracking. -

-

-redirect

-

Description: Intercepts transaction by issuing an external -(client-visible) redirection to the given location.. -

Action Group: Disruptive -

Example: -

-
SecRule REQUEST_HEADERS:User-Agent "Test" "phase:1,id:130,log,redirect:http://www.example.com/failed.html"
-
-

If the status action is present on the same rule, and its value can -be used for a redirection (i.e., is one of the following: 301, 302, 303, - or 307), the value will be used for the redirection status code. -Otherwise, status code 302 will be used. -

-

rev

-

Description: Specifies rule revision. It is useful in -combination with the id action to provide an indication that a rule has -been changed. -

Action Group: Meta-data -

Example: -

-
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "(?:(?:[\;\|\`]\W*?\bcc|\b(wget|curl))\b|\/cc(?:[\'\"\|\;\`\-\s]|$))" \
-	                "phase:2,rev:'2.1.3',capture,t:none,t:normalisePath,t:lowercase,ctl:auditLogParts=+E,block,msg:'System Command Injection',id:'950907',tag:'WEB_ATTACK/COMMAND_INJECTION',tag:'WASCTC/WASC-31',tag:'OWASP_TOP_10/A1',tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.command_injection_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/COMMAND_INJECTION-%{matched_var_name}=%{tx.0},skipAfter:END_COMMAND_INJECTION1"
-
-
Note 
This action is used in combination with the - id action to allow the same rule ID to be used after changes take place - but to still provide some indication the rule changed. -
-

sanitiseArg

-

Description: Prevents sensitive request parameter data from -being logged to audit log. Each byte of the named parameter(s) is -replaced with an asterisk. -

Action Group: Non-disruptive -

Example: -

-
# Never log passwords 
-SecAction "nolog,phase:2,id:131,sanitiseArg:password,sanitiseArg:newPassword,sanitiseArg:oldPassword"
-
-
Note 
The sanitize actions affect only the data -as it is logged to audit log. High-level debug logs may contain -sensitive data. Apache access log may contain sensitive data placed in -the request URI. -
-

sanitiseMatched

-

Description: Prevents the matched variable (request argument, -request header, or response header) from being logged to audit log. Each - byte of the named parameter(s) is replaced with an asterisk. -

Action Group: Non-disruptive -

Example: This action can be used to sanitise arbitrary -transaction elements when they match a condition. For example, the -example below will sanitise any argument that contains the word password - in the name. -

-
SecRule ARGS_NAMES password nolog,pass,id:132,sanitiseMatched
-
-
Note 
The sanitize actions affect only the data -as it is logged to audit log. High-level debug logs may contain -sensitive data. Apache access log may contain sensitive data placed in -the request URI. -
-

sanitiseMatchedBytes

-

Description: Prevents the matched string in a variable from -being logged to audit log. Each or a range of bytes of the named -parameter(s) is replaced with an asterisk. -

Action Group: Non-disruptive -

Example: This action can be used to sanitise arbitrary -transaction elements when they match a condition. For example, the -example below will sanitise the credit card number. -

-
  • sanitiseMatchedBytes -- This would x out only the bytes that -matched. -
  • sanitiseMatchedBytes:1/4 -- This would x out the bytes that -matched, but keep the first byte and last 4 bytes -
-
# Detect credit card numbers in parameters and 
-# prevent them from being logged to audit log 
-SecRule ARGS "@verifyCC \d{13,16}" "phase:2,id:133,nolog,capture,pass,msg:'Potential credit card number in request',sanitiseMatchedBytes"
-SecRule RESPONSE_BODY "@verifyCC \d{13,16}" "phase:4,id:134,t:none,log,capture,block,msg:'Potential credit card number is response body',sanitiseMatchedBytes:0/4"
-
-
Note 
The sanitize actions affect only the data -as it is logged to audit log. High-level debug logs may contain -sensitive data. Apache access log may contain sensitive data placed in -the request URI. You must use capture action with sanitiseMatchedBytes, -so the operator must support capture action. ie: @rx, @verifyCC. -
-

sanitiseRequestHeader

-

Description: Prevents a named request header from being logged - to audit log. Each byte of the named request header is replaced with an - asterisk.. -

Action Group: Non-disruptive -

Example: This will sanitise the data in the Authorization -header. -

-
SecAction "phase:1,nolog,pass,id:135,sanitiseRequestHeader:Authorization"
-
-
Note 
The sanitize actions affect only the data -as it is logged to audit log. High-level debug logs may contain -sensitive data. Apache access log may contain sensitive data placed in -the request URI. -
-

sanitiseResponseHeader

-

Description: Prevents a named response header from being -logged to audit log. Each byte of the named response header is replaced -with an asterisk. -

Action Group: Non-disruptive -

Example: This will sanitise the Set-Cookie data sent to -the client. -

-
SecAction "phase:3,nolog,pass,id:136,sanitiseResponseHeader:Set-Cookie"
-
-
Note 
The sanitize actions affect only the data -as it is logged to audit log. High-level debug logs may contain -sensitive data. Apache access log may contain sensitive data placed in -the request URI. -
-

-severity

-

Description: Assigns severity to the rule in which it is used. -

Action Group: Meta-data -

Example: -

-
SecRule REQUEST_METHOD "^PUT$" "id:340002,rev:1,severity:CRITICAL,msg:'Restricted HTTP function'"
-
-

Severity values in ModSecurity follows the numeric scale of syslog -(where 0 is the most severe). The data below is used by the OWASP -ModSecurity Core Rule Set (CRS): -

-
  • 0 - EMERGENCY: is generated from correlation of anomaly -scoring data where there is an inbound attack and an outbound leakage. -
  • 1 - ALERT: is generated from correlation where there is -an inbound attack and an outbound application level error. -
  • 2 - CRITICAL: Anomaly Score of 5. Is the highest -severity level possible without correlation. It is normally generated -by the web attack rules (40 level files). -
  • 3 - ERROR: Error - Anomaly Score of 4. Is generated -mostly from outbound leakage rules (50 level files). -
  • 4 - WARNING: Anomaly Score of 3. Is generated by -malicious client rules (35 level files). -
  • 5 - NOTICE: Anomaly Score of 2. Is generated by the -Protocol policy and anomaly files. -
  • 6 - INFO -
  • 7 - DEBUG -
-

It is possible to specify severity levels using either the numerical -values or the text values, but you should always specify severity levels - using the text values, because it is difficult to remember what a -number stands for. The use of the numerical values is deprecated as of -version 2.5.0 and may be removed in one of the subsequent major updates. -

-

setuid

-

Description: Special-purpose action that initializes the USER -collection using the username provided as parameter. -

Action Group: Non-disruptive -

Example: -

-
SecRule ARGS:username ".*" "phase:2,id:137,t:none,pass,nolog,noauditlog,capture,setvar:session.username=%{TX.0},setuid:%{TX.0}"
-
-

After initialization takes place, the variable USERID will be -available for use in the subsequent rules. This action understands -application namespaces (configured using SecWebAppId), and will use one -if it is configured. -

-

setrsc

-

Description: Special-purpose action that initializes the -RESOURCE collection using a key provided as parameter. -

Action Group: Non-disruptive -

Example: -

-
SecAction "phase:1,pass,id:3,log,setrsc:'abcd1234'"
-
-

This action understands application namespaces (configured using -SecWebAppId), and will use one if it is configured. -

-

setsid

-

Description: Special-purpose action that initializes the -SESSION collection using the session token provided as parameter. -

Action Group: Non-disruptive -

Example: -

-
# Initialise session variables using the session cookie value 
-SecRule REQUEST_COOKIES:PHPSESSID !^$ "nolog,pass,id:138,setsid:%{REQUEST_COOKIES.PHPSESSID}"
-
-

Note -

After the initialization takes place, the variable SESSIONID will - be available for use in the subsequent rules. This action understands -application namespaces (configured using SecWebAppId), and will use one -if it is configured. -

-

setenv

-

Description: Creates, removes, and updates environment -variables that can be accessed by Apache. -

Action Group: Non-disruptive -

Examples: -

-
SecRule RESPONSE_HEADERS:/Set-Cookie2?/ "(?i:(j?sessionid|(php)?sessid|(asp|jserv|jw)?session[-_]?(id)?|cf(id|token)|sid))" "phase:3,t:none,pass,id:139,nolog,setvar:tx.sessionid=%{matched_var}"
-SecRule TX:SESSIONID "!(?i:\;? ?httponly;?)" "phase:3,id:140,t:none,setenv:httponly_cookie=%{matched_var},pass,log,auditlog,msg:'AppDefect: Missing HttpOnly Cookie Flag.'"
-
-Header set Set-Cookie "%{httponly_cookie}e; HTTPOnly" env=httponly_cookie
-
-
Note 
When used in a chain this action will be -execute when an individual rule matches and not the entire chain. -
-

setvar

-

Description: Creates, removes, or updates a variable. Variable - names are case-insensitive. -

Action Group: Non-disruptive -

Examples: -To create a variable and set its value to 1 (usually used for setting -flags), use: setvar:TX.score -

To create a variable and initialize it at the same time, use: setvar:TX.score=10 -

To remove a variable prefix the name with exclamation mark, use: setvar:!TX.score -

To increase or decrease variable value, use + and - characters in - front of a numerical value: setvar:TX.score=+5 -

Example from OWASP CRS: -

-
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "\bsys\.user_catalog\b" \
-		"phase:2,rev:'2.1.3',capture,t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,t:replaceComments,t:compressWhiteSpace,ctl:auditLogParts=+E, \
-block,msg:'Blind SQL Injection Attack',id:'959517',tag:'WEB_ATTACK/SQL_INJECTION',tag:'WASCTC/WASC-19',tag:'OWASP_TOP_10/A1',tag:'OWASP_AppSensor/CIE1', \
-tag:'PCI/6.5.2',logdata:'%{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.sql_injection_score=+%{tx.critical_anomaly_score}, \
-setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/SQL_INJECTION-%{matched_var_name}=%{tx.0}"
-
-
Note 
When used in a chain this action will be -execute when an individual rule matches and not the entire chain. -
-

skip

-

Description: Skips one or more rules (or chains) on successful - match. -

Action Group: Flow -

Example: -

-
# Require Accept header, but not from access from the localhost 
-SecRule REMOTE_ADDR "^127\.0\.0\.1$" "phase:1,skip:1,id:141" 
-
-# This rule will be skipped over when REMOTE_ADDR is 127.0.0.1 
-SecRule &REQUEST_HEADERS:Accept "@eq 0" "phase:1,id:142,deny,msg:'Request Missing an Accept Header'"
-
-

The skip action works only within the current processing phase and -not necessarily in the order in which the rules appear in the -configuration file. If you place a phase 2 rule after a phase 1 rule -that uses skip, it will not skip over the phase 2 rule. It will skip -over the next phase 1 rule that follows it in the phase. -

-

-skipAfter

-

Description: Skips one or more rules (or chains) on a successful -match, resuming rule execution with the first rule that follows the rule - (or marker created by SecMarker) with the provided ID. -

Action Group: Flow -

Example: The following rules implement the same logic as -the skip example, but using skipAfter: -

-
# Require Accept header, but not from access from the localhost 
-SecRule REMOTE_ADDR "^127\.0\.0\.1$" "phase:1,id:143,skipAfter:IGNORE_LOCALHOST" 
-
-# This rule will be skipped over when REMOTE_ADDR is 127.0.0.1 
-SecRule &REQUEST_HEADERS:Accept "@eq 0" "phase:1,deny,id:144,msg:'Request Missing an Accept Header'" 
-SecMarker IGNORE_LOCALHOST
-
-

Example from the OWASP ModSecurity CRS: -

-
SecMarker BEGIN_HOST_CHECK
-
-	SecRule &REQUEST_HEADERS:Host "@eq 0" \
-    		"skipAfter:END_HOST_CHECK,phase:2,rev:'2.1.3',t:none,block,msg:'Request Missing a Host Header',id:'960008',tag:'PROTOCOL_VIOLATION/MISSING_HEADER_HOST',tag:'WASCTC/WASC-21', \
-tag:'OWASP_TOP_10/A7',tag:'PCI/6.5.10',severity:'5',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score}, \
-setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}"
-
-	SecRule REQUEST_HEADERS:Host "^$" \
-    		"phase:2,rev:'2.1.3',t:none,block,msg:'Request Missing a Host Header',id:'960008',tag:'PROTOCOL_VIOLATION/MISSING_HEADER_HOST',tag:'WASCTC/WASC-21',tag:'OWASP_TOP_10/A7', \
-tag:'PCI/6.5.10',severity:'5',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.protocol_violation_score=+%{tx.notice_anomaly_score}, \
-setvar:tx.%{rule.id}-PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}"
-
-SecMarker END_HOST_CHECK
-
-

The skipAfter action works only within the current processing phase -and not necessarily the order in which the rules appear in the -configuration file. If you place a phase 2 rule after a phase 1 rule -that uses skip, it will not skip over the phase 2 rule. It will skip -over the next phase 1 rule that follows it in the phase. -

-

status

-

Description: Specifies the response status code to use with -actions deny and redirect. -

Action Group: Data -

Example: -

-
# Deny with status 403
-SecDefaultAction "phase:1,log,deny,id:145,status:403"
-
-

Status actions defined in Apache scope locations (such as Directory, -Location, etc...) may be superseded by phase:1 action settings. The -Apache ErrorDocument directive will be triggered if present in the -configuration. Therefore if you have previously defined a custom error -page for a given status then it will be executed and its output -presented to the user. -

-

t

-

Description: This action is used to specify the transformation - pipeline to use to transform the value of each variable used in the -rule before matching. -

Action Group: Non-disruptive -

Example: -

-
SecRule ARGS "(asfunction|javascript|vbscript|data|mocha|livescript):" "id:146,t:none,t:htmlEntityDecode,t:lowercase,t:removeNulls,t:removeWhitespace"
-
-

Any transformation functions that you specify in a SecRule will be -added to the previous ones specified in SecDefaultAction. It is -recommended that you always use t:none in your rules, which prevents -them depending on the default configuration. -

-

tag

-

Description: Assigns a tag (category) to a rule or a chain. -

Action Group: Meta-data -

Example: -

-
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "\bgetparentfolder\b" \
-	"phase:2,rev:'2.1.3',capture,t:none,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,msg:'Cross-site Scripting (XSS) Attack',id:'958016',tag:'WEB_ATTACK/XSS',tag:'WASCTC/WASC-8',tag:'WASCTC/WASC-22',tag:'OWASP_TOP_10/A2',tag:'OWASP_AppSensor/IE1',tag:'PCI/6.5.1',logdata:'% \
-{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+%{tx.critical_anomaly_score},setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{tx.0}"
-
-

The tag information appears along with other rule metadata. The -purpose of the tagging mechanism to allow easy automated categorization -of events. Multiple tags can be specified on the same rule. Use forward -slashes to create a hierarchy of categories (as in the example). Since -ModSecurity 2.6.0 tag supports macro expansion. -

-

ver

-

Description: Specifies the rule set version. -

Action Group: Meta-data -

Version: 2.7 -

Example: -

-
SecRule REQUEST_FILENAME|ARGS_NAMES|ARGS|XML:/* "\bgetparentfolder\b" \
-	"phase:2,ver:'CRS/2.2.4,capture,t:none,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,ctl:auditLogParts=+E,block,msg:'Cross-site Scripting (XSS) Attack',id:'958016',tag:'WEB_ATTACK/XSS',tag:'WASCTC/WASC-8',tag:'WASCTC/WASC-22',tag:'OWASP_TOP_10/A2',tag:'OWASP_AppSensor/IE1',tag:'PCI/6.5.1',logdata:'% \
-{TX.0}',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.xss_score=+%{tx.critical_anomaly_score},setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/XSS-%{matched_var_name}=%{tx.0}"
-
-

xmlns

-

Description: Configures an XML namespace, which will be used -in the execution of XPath expressions. -

Action Group: Data -

Example: -

-
SecRule REQUEST_HEADERS:Content-Type "text/xml" "phase:1,id:147,pass,ctl:requestBodyProcessor=XML,ctl:requestBodyAccess=On, \
-    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
-SecRule XML:/soap:Envelope/soap:Body/q1:getInput/id() "123" phase:2,deny,id:148
-
-

-Operators

-

This section documents the operators currently available in -ModSecurity. -

-

- beginsWith

-

Description: Returns true if the parameter string is found at -the beginning of the input. Macro expansion is performed on the -parameter string before comparison. -

Example: -

-
# Detect request line that does not begin with "GET" 
-SecRule REQUEST_LINE "!@beginsWith GET" "id:149"
-
-
-

-contains

-

Description: Returns true if the parameter string is found -anywhere in the input. Macro expansion is performed on the parameter -string before comparison. -

Example: -

-
# Detect ".php" anywhere in the request line 
-SecRule REQUEST_LINE "@contains .php" "id:150"
-
-

containsWord

-

Description: Returns true if the parameter string (with word -boundaries) is found anywhere in the input. Macro expansion is performed - on the parameter string before comparison. -

Example: -

-
# Detect "select" anywhere in ARGS 
-SecRule ARGS "@containsWord select" "id:151"
-
-

Would match on -
--1 union select -BENCHMARK(2142500,MD5(CHAR(115,113,108,109,97,112))) FROM wp_users WHERE - ID=1 and (ascii(substr(user_login,1,1))&0x01=0) from wp_users where - ID=1-- -

But not on -
-Your site has a wide selection of computers. -

-

-endsWith

-

Description: Returns true if the parameter string is found at -the end of the input. Macro expansion is performed on the parameter -string before comparison. -

Example: -

-
# Detect request line that does not end with "HTTP/1.1" 
-SecRule REQUEST_LINE "!@endsWith HTTP/1.1" "id:152"
-
-

eq

-

Description: Performs numerical comparison and returns true if - the input value is equal to the provided parameter. Macro expansion is -performed on the parameter string before comparison. -

Example: -

-
# Detect exactly 15 request headers 
-SecRule &REQUEST_HEADERS_NAMES "@eq 15" "id:153"
-
-

ge

-

Description: Performs numerical comparison and returns true if - the input value is greater than or equal to the provided parameter. -Macro expansion is performed on the parameter string before comparison. -

Example: -

-
# Detect 15 or more request headers 
-SecRule &REQUEST_HEADERS_NAMES "@ge 15" "id:154"
-
-

-geoLookup

-

Description: Performs a geolocation lookup using the IP -address in input against the geolocation database previously configured -using SecGeoLookupDb. If the lookup is successful, the obtained -information is captured in the GEO collection. -

Example: -The geoLookup operator matches on success and is thus best used in -combination with nolog,pass. If you wish to block on a failed lookup -(which may be over the top, depending on how accurate the geolocation -database is), the following example demonstrates how best to do it: -

-
# Configure geolocation database 
-SecGeoLookupDb /path/to/GeoLiteCity.dat 
-... 
-# Lookup IP address 
-SecRule REMOTE_ADDR "@geoLookup" "phase:1,id:155,nolog,pass"
-
-# Block IP address for which geolocation failed
- SecRule &GEO "@eq 0" "phase:1,id:156,deny,msg:'Failed to lookup IP'"
-
-

See the GEO variable for an example and more information on various -fields available. -

-

-gsbLookup

-

Description: Performs a local lookup of Google's Safe Browsing - using URLs in input against the GSB database previously configured -using SecGsbLookupDb. When combined with capture operator it will save -the matched url into tx.0 variable. -

Syntax: SecRule TARGET "@gsbLookup REGEX" ACTIONS -

Version: 2.6 -

Example: -The gsbLookup operator matches on success and is thus best used in -combination with a block or redirect action. If you wish to block on -successful lookups, the following example demonstrates how best to do -it: -

-
# Configure Google Safe Browsing database 
-SecGsbLookupDb /path/to/GsbMalware.dat 
-... 
-# Check response bodies for malicious links
-SecRule RESPONSE_BODY "@gsbLookup =\"https?\:\/\/(.*?)\"" "phase:4,id:157,capture,log,block,msg:'Bad url detected in RESPONSE_BODY (Google Safe Browsing Check)',logdata:'http://www.google.com/safebrowsing/diagnostic?site=%{tx.0}'"
-
-

gt

-

Description: Performs numerical comparison and returns true if - the input value is greater than the operator parameter. Macro expansion - is performed on the parameter string before comparison. -

Example: -

-
# Detect more than 15 headers in a request 
-SecRule &REQUEST_HEADERS_NAMES "@gt 15" "id:158"
-
-

inspectFile

-

Description: Executes an external program for every variable -in the target list. The contents of the variable is provided to the -script as the first parameter on the command line. The program must be -specified as the first parameter to the operator. As of version 2.5.0, -if the supplied program filename is not absolute, it is treated as -relative to the directory in which the configuration file resides. Also -as of version 2.5.0, if the filename is determined to be a Lua script -(based on its .lua extension), the script will be processed by the -internal Lua engine. Internally processed scripts will often run faster -(there is no process creation overhead) and have full access to the -transaction context of ModSecurity. -

The @inspectFile operator was initially designed for file -inspection (hence the name), but it can also be used in any situation -that requires decision making using external logic. -

The OWASP ModSecurity Core Rule Set (CRS) includes a utility -script in the /util directory called runav.pl [13] that allows the file approval mechanism to -integrate with the ClamAV virus scanner. This is especially handy to -prevent viruses and exploits from entering the web server through file -upload. -

-
#!/usr/bin/perl
-#
-# runav.pl
-# Copyright (c) 2004-2011 Trustwave
-#
-# This script is an interface between ModSecurity and its
-# ability to intercept files being uploaded through the
-# web server, and ClamAV
-
-
-$CLAMSCAN = "clamscan";
-
-if ($#ARGV != 0) {
-    print "Usage: modsec-clamscan.pl <filename>\n";
-    exit;
-}
-
-my ($FILE) = shift @ARGV;
-
-$cmd = "$CLAMSCAN --stdout --disable-summary $FILE";
-$input = `$cmd`;
-$input =~ m/^(.+)/;
-$error_message = $1;
-
-$output = "0 Unable to parse clamscan output [$1]";
-
-if ($error_message =~ m/: Empty file\.?$/) {
-    $output = "1 empty file";
-}
-elsif ($error_message =~ m/: (.+) ERROR$/) {
-    $output = "0 clamscan: $1";
-}
-elsif ($error_message =~ m/: (.+) FOUND$/) {
-    $output = "0 clamscan: $1";
-}
-elsif ($error_message =~ m/: OK$/) {
-    $output = "1 clamscan: OK";
-}
-
-print "$output\n";
-
-
-

Example: Using the runav.pl script: -

-
# Execute external program to validate uploaded files 
-SecRule FILES_TMPNAMES "@inspectFile /path/to/util/runav.pl" "id:159"
-
-

Example of using Lua script (placed in the same directory as the -configuration file): -

-
SecRule FILES_TMPNANMES "@inspectFile inspect.lua" "id:160"
-
-

The contents of inspect.lua: -

-
function main(filename)
-    -- Do something to the file to verify it. In this example, we
-    -- read up to 10 characters from the beginning of the file.
-    local f = io.open(filename, "rb");
-    local d = f:read(10);
-    f:close();
-   
-    -- Return null if there is no reason to believe there is ansything
-    -- wrong with the file (no match). Returning any text will be taken
-    -- to mean a match should be trigerred.
-    return null;
-end
-
-

Reference: http://blog.spiderlabs.com/2010/10/advanced-topic-of-the-week-preventing-malicious-pdf-file-uploads.html -

-

-ipMatch

-

Description: Performs a fast ipv4 or ipv6 match of REMOTE_ADDR - variable data. Can handle the following formats: -

-
  • Full IPv4 Address - 192.168.1.100 -
  • Network Block/CIDR Address - 192.168.1.0/24 -
  • Full IPv6 Address - 2001:db8:85a3:8d3:1319:8a2e:370:7348 -
  • Network Block/CIDR Address - -2001:db8:85a3:8d3:1319:8a2e:370:0/24 -
-

Examples: -

Individual Address: -

-
SecRule REMOTE_ADDR "@ipMatch 192.168.1.100" "id:161"
-
-

Multiple Addresses w/network block: -

-
SecRule REMOTE_ADDR "@ipMatch 192.168.1.100,192.168.1.50,10.10.50.0/24" "id:162"
-
-

-ipMatchF

-

short alias for ipMatchFromFile -

-

ipMatchFromFile

-

Description: Performs a fast ipv4 or ipv6 match of REMOTE_ADDR - variable, loading data from a file. Can handle the following formats: -

-
  • Full IPv4 Address - 192.168.1.100 -
  • Network Block/CIDR Address - 192.168.1.0/24 -
  • Full IPv6 Address - 2001:db8:85a3:8d3:1319:8a2e:370:7348 -
  • Network Block/CIDR Address - -2001:db8:85a3:8d3:1319:8a2e:370:0/24 -
-

Examples: -

-
SecRule REMOTE_ADDR "@ipMatch ips.txt" "id:163"
-
-

The file ips.txt may contain: -

-
192.168.0.1
-172.16.0.0/16
-10.0.0.0/8
-
-

le

-

Description: Performs numerical comparison and returns true if - the input value is less than or equal to the operator parameter. Macro -expansion is performed on the parameter string before comparison. -

Example: -

-
# Detect 15 or fewer headers in a request 
-SecRule &REQUEST_HEADERS_NAMES "@le 15" "id:164"
-
-

lt

-

Description: Performs numerical comparison and returns true if - the input value is less than to the operator parameter. Macro expansion - is performed on the parameter string before comparison. -

Example: -

-
# Detect fewer than 15 headers in a request 
-SecRule &REQUEST_HEADERS_NAMES "@lt 15" "id:165"
-
-

pm

-

Description: Performs a case-insensitive match of the provided - phrases against the desired input value. The operator uses a set-based -matching algorithm (Aho-Corasick), which means that it will match any -number of keywords in parallel. When matching of a large number of -keywords is needed, this operator performs much better than a regular -expression. -

Example: -

-
# Detect suspicious client by looking at the user agent identification 
-SecRule REQUEST_HEADERS:User-Agent "@pm WebZIP WebCopier Webster WebStripper ... SiteSnagger ProWebWalker CheeseBot" "id:166"
-
-
Note 
Starting on ModSecurity v2.6.0 this -operator supports a snort/suricata content style. ie: "@pm A|42|C|44|F". -
-

pmf

-

Short alias for pmFromFile. -

-

- pmFromFile

-

Description: Performs a case-insensitive match of the provided - phrases against the desired input value. The operator uses a set-based -matching algorithm (Aho-Corasick), which means that it will match any -number of keywords in parallel. When matching of a large number of -keywords is needed, this operator performs much better than a regular -expression. -

This operator is the same as @pm, except that it takes a list of -files as arguments. It will match any one of the phrases listed in the -file(s) anywhere in the target value. -

Example: -

-
# Detect suspicious user agents using the keywords in 
-# the files /path/to/blacklist1 and blacklist2 (the latter 
-# must be placed in the same folder as the configuration file) 
-SecRule REQUEST_HEADERS:User-Agent "@pm /path/to/blacklist1 blacklist2" "id:167"
-
-

Notes: -

-
  1. Files must contain exactly one phrase per line. End of line -markers (both LF and CRLF) will be stripped from each phrase and any -whitespace trimmed from both the beginning and the end. Empty lines and -comment lines (those beginning with the # character) will be ignored. -
  2. To allow easier inclusion of phrase files with rule sets, -relative paths may be used to the phrase files. In this case, the path -of the file containing the rule is prepended to the phrase file path. -
  3. The @pm operator phrases do not support metacharacters. -
  4. Because this operator does not check for boundaries when -matching, false positives are possible in some cases. For example, if -you want to use @pm for IP address matching, the phrase 1.2.3.4 will -potentially match more than one IP address (e.g., it will also match -1.2.3.40 or 1.2.3.41). To avoid the false positives, you can use your -own boundaries in phrases. For example, use /1.2.3.4/ instead of just -1.2.3.4. Then, in your rules, also add the boundaries where appropriate. - You will find a complete example in the example. -
-
# Prepare custom REMOTE_ADDR variable 
-SecAction "phase:1,id:168,nolog,pass,setvar:tx.REMOTE_ADDR=/%{REMOTE_ADDR}/"
-
-# Check if REMOTE_ADDR is blacklisted 
-SecRule TX:REMOTE_ADDR "@pmFromFile blacklist.txt" "phase:1,id:169,deny,msg:'Blacklisted IP address'" 
-
-

The file blacklist.txt may contain: -

-
# ip-blacklist.txt contents:
-# NOTE: All IPs must be prefixed/suffixed with "/" as the rules
-#   will add in this character as a boundary to ensure
-#   the entire IP is matched.
-# SecAction "phase:1,id:170,pass,nolog,setvar:tx.remote_addr='/%{REMOTE_ADDR}/'"
-/1.2.3.4/ 
-/5.6.7.8/
-
-
Warning 
Before ModSecurity 2.5.12, the -@pmFromFile operator understood only the LF line endings and did not -trim the whitespace from phrases. If you are using an older version of -ModSecurity, you should take care when editing the phrase files to avoid - using the undesired characters in patterns.e files should be one phrase - per line. End of line markers will be stripped from the phrases (LF and - CRLF), and whitespace is trimmed from both sides of the phrases. Empty -lines and comment lines (beginning with a '#') are ignored. To allow -easier inclusion of phrase files with rulesets, relative paths may be -used to the phrase files. In this case, the path of the file containing -the rule is prepended to the phrase file path. -
-


-

-
Note 
Starting on ModSecurity v2.6.0 this -operator supports a snort/suricata content style. ie: "A|42|C|44|F". -
-

rbl

-

Description: Looks up the input value in the RBL (real-time -block list) given as parameter. The parameter can be an IPv4 address or a - hostname. -

Example: -

-
SecRule REMOTE_ADDR "@rbl sbl-xbl.spamhaus.org" "phase:1,id:171,t:none,pass,nolog,auditlog,msg:'RBL Match for SPAM Source',tag:'AUTOMATION/MALICIOUS',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.automation_score=+%{tx.warning_anomaly_score},setvar:tx.anomaly_score=+%{tx.warning_anomaly_score}, \
-setvar:tx.%{rule.id}-AUTOMATION/MALICIOUS-%{matched_var_name}=%{matched_var},setvar:ip.spammer=1,expirevar:ip.spammer=86400,setvar:ip.previous_rbl_check=1,expirevar:ip.previous_rbl_check=86400,skipAfter:END_RBL_CHECK"
-
-
Note 
If the RBL used is dnsbl.httpbl.org -(Honeypot Project RBL) then the SecHttpBlKey directive must specify the -user's registered API key. -
Note 
If the RBL used is either multi.uribl.com -or zen.spamhaus.org combined RBLs, it is possible to also parse the -return codes in the last octet of the DNS response to identify which -specific RBL the IP was found in. -
-

rsub

-

Description: Performs regular expression data substitution -when applied to either the STREAM_INPUT_BODY or STREAM_OUTPUT_BODY -variables. This operator also supports macro expansion. Starting with -ModSecurity 2.7.0 this operator supports the syntax |hex| allowing users - to use special chars like \n \r -

Syntax: @rsub s/regex/str/[id] -

Examples: -Removing HTML Comments from response bodies: -

-
SecStreamOutBodyInspection On
-SecRule STREAM_OUTPUT_BODY "@rsub s/<!--.*?-->/ /" "phase:4,id:172,t:none,nolog,pass"
-
-
Note 
If you plan to manipulate live data by -using @rsub with the STREAM_ variables, you must also enable -SecContentInjection directive. -
-

Regular expressions are handled by the PCRE library [14]. ModSecurity -compiles its regular expressions with the following settings: -

-
  1. The entire input is treated as a single line, even when there -are newline characters present. -
  2. All matches are case-sensitive. If you wish to perform -case-insensitive matching, you can either use the lowercase -transformation function or force case-insensitive matching by prefixing -the regular expression pattern with the (?i) modifier (a PCRE feature; -you will find many similar features in the PCRE documentation). Also a -flag [d] should be used if you want to escape the regex string chars -when use macro expansion. -
  3. The PCRE_DOTALL and PCRE_DOLLAR_ENDONLY flags are set during -compilation, meaning that a single dot will match any character, -including the newlines, and a $ end anchor will not match a trailing -newline character. -
-

Regular expressions are a very powerful tool. You are strongly -advised to read the PCRE documentation to get acquainted with its -features. -

-

rx

-

Description: Performs a regular expression match of the -pattern provided as parameter. This is the default operator; the -rules that do not explicitly specify an operator default to @rx. -

Examples: -

-
# Detect Nikto 
-SecRule REQUEST_HEADERS:User-Agent "@rx nikto" phase:1,id:173,t:lowercase
-
-# Detect Nikto with a case-insensitive pattern 
-SecRule REQUEST_HEADERS:User-Agent "@rx (?i)nikto" phase:1,id:174,t:none
-
-# Detect Nikto with a case-insensitive pattern 
-SecRule REQUEST_HEADERS:User-Agent "(?i)nikto" "id:175"
-
-

Regular expressions are handled by the PCRE library [15]. ModSecurity -compiles its regular expressions with the following settings: -

-
  1. The entire input is treated as a single line, even when there -are newline characters present. -
  2. All matches are case-sensitive. If you wish to perform -case-insensitive matching, you can either use the lowercase -transformation function or force case-insensitive matching by prefixing -the regular expression pattern with the (?i) modifier (a PCRE feature; -you will find many similar features in the PCRE documentation). -
  3. The PCRE_DOTALL and PCRE_DOLLAR_ENDONLY flags are set during -compilation, meaning that a single dot will match any character, -including the newlines, and a $ end anchor will not match a trailing -newline character. -
-

Regular expressions are a very powerful tool. You are strongly -advised to read the PCRE documentation to get acquainted with its -features. -

-

streq

-

Description: Performs a string comparison and returns true if -the parameter string is identical to the input string. Macro expansion -is performed on the parameter string before comparison. -

Example: -

-
# Detect request parameters "foo" that do not # contain "bar", exactly. 
-SecRule ARGS:foo "!@streq bar" "id:176"
-
-

-strmatch

-

Description: Performs a string match of the provided word -against the desired input value. The operator uses the pattern matching - Boyer-Moore-Horspool algorithm, which means that it is a single pattern - matching operator. This operator performs much better than a regular -expression. -

Example: -

-
# Detect suspicious client by looking at the user agent identification 
-SecRule REQUEST_HEADERS:User-Agent "@strmatch WebZIP" "id:177"
-
-


-

-
Note 
Starting on ModSecurity v2.6.0 this -operator supports a snort/suricata content style. ie: "@strmatch -A|42|C|44|F". -
-

validateByteRange

-

Description: Validates that the byte values used in input fall - into the range specified by the operator parameter. This operator -matches on an input value that contains bytes that are not in the -specified range. -

Example: -

-
# Enforce very strict byte range for request parameters (only 
-# works for the applications that do not use the languages other 
-# than English). 
-SecRule ARGS "@validateByteRange 10, 13, 32-126" "id:178"
-
-

The validateByteRange is most useful when used to detect the presence - of NUL bytes, which don’t have a legitimate use, but which are often -used as an evasion technique. -

-
# Do not allow NUL bytes 
-SecRule ARGS "@validateByteRange 1-255" "id:179"
-
-
Note 
You can force requests to consist only of -bytes from a certain byte range. This can be useful to avoid stack -overflow attacks (since they usually contain "random" binary content). -Default range values are 0 and 255, i.e. all byte values are allowed. -This directive does not check byte range in a POST payload when -multipart/form-data encoding (file upload) is used. Doing so would -prevent binary files from being uploaded. However, after the parameters -are extracted from such request they are checked for a valid range. -
-

validateByteRange is similar to the ModSecurity 1.X -SecFilterForceByteRange Directive however since it works in a rule -context, it has the following differences: -

-
  • You can specify a different range for different variables. -
  • It has an "event" context (id, msg....) -
  • It is executed in the flow of rules rather than being a built -in pre-check. -
-

validateDTD

-

Description: Validates the XML DOM tree against the supplied -DTD. The DOM tree must have been built previously using the XML request -body processor. This operator matches when the validation fails. -

Example: -

-
# Parse the request bodies that contain XML 
-SecRule REQUEST_HEADERS:Content-Type ^text/xml$ "phase:1,id:180,nolog,pass,t:lowercase,ctl:requestBodyProcessor=XML"
-
-# Validate XML payload against DTD 
-SecRule XML "@validateDTD /path/to/xml.dtd" "phase:2,id:181,deny,msg:'Failed DTD validation'"
-
-

validateEncryption

-

Description: Validates REQUEST_URI that contains data -protected by the encryption engine. -

Example: -

-
# Validates requested URI that matches a regular expression.
-SecRule REQUEST_URI "@validateEncryption "product_info|product_list" "phase:1,deny,id:123456"
-
-

validateSchema

-

Description: Validates the XML DOM tree against the supplied -XML Schema. The DOM tree must have been built previously using the XML -request body processor. This operator matches when the validation fails. -

Example: -

-
# Parse the request bodies that contain XML 
-SecRule REQUEST_HEADERS:Content-Type ^text/xml$ "phase:1,id:190,nolog,pass,t:lowercase,ctl:requestBodyProcessor=XML"
-
-# Validate XML payload against DTD 
-SecRule XML "@validateSchema /path/to/xml.xsd" "phase:2,id:191,deny,msg:'Failed DTD validation'"
-
-

validateUrlEncoding

-

Description: Validates the URL-encoded characters in the -provided input string. -

Example: -

-
# Validate URL-encoded characters in the request URI 
-SecRule REQUEST_URI_RAW "@validateUrlEncoding" "id:192"
-
-

ModSecurity will automatically decode the URL-encoded characters in -request parameters, which means that there is little sense in applying -the @validateUrlEncoding operator to them —that is, unless you know that - some of the request parameters were URL-encoded more than once. Use -this operator against raw input, or against the input that you know is -URL-encoded. For example, some applications will URL-encode cookies, -although that’s not in the standard. Because it is not in the standard, -ModSecurity will neither validate nor decode such encodings. -

-

validateUtf8Encoding

-

Description: Check whether the input is a valid UTF-8 string. -

Example: -

-
# Make sure all request parameters contain only valid UTF-8 
-SecRule ARGS "@validateUtf8Encoding" "id:193"
-
-

The @validateUtf8Encoding operator detects the following problems: -

-
Not enough bytes 
UTF-8 supports two-, three-, -four-, five-, and six-byte encodings. ModSecurity will locate cases when - one or more bytes is/are missing from a character. -
Invalid characters 
The two most significant -bits in most characters should be fixed to 0x80. Some attack techniques -use different values as an evasion technique. -
Overlong characters 
ASCII characters are mapped - directly into UTF-8, which means that an ASCII character is one UTF-8 -character at the same time. However, in UTF-8 many ASCII characters can -also be encoded with two, three, four, five, and six bytes. This is no -longer legal in the newer versions of Unicode, but many older -implementations still support it. The use of overlong UTF-8 characters -is common for evasion. -
-
Notes 
-
-
  • Most, but not all applications use UTF-8. If you are dealing -with an application that does, validating that all request parameters -are valid UTF-8 strings is a great way to prevent a number of evasion -techniques that use the assorted UTF-8 weaknesses. False positives are -likely if you use this operator in an application that does not use -UTF-8. -
  • Many web servers will also allow UTF-8 in request URIs. If -yours does, you can verify the request URI using @validateUtf8Encoding. -
-

-verifyCC

-

Description: Detects credit card numbers in input. This -operator will first use the supplied regular expression to perform an -initial match, following up with the Luhn algorithm calculation to -minimize false positives. -

Example: -

-
# Detect credit card numbers in parameters and 
-# prevent them from being logged to audit log 
-SecRule ARGS "@verifyCC \d{13,16}" "phase:2,id:194,nolog,pass,msg:'Potential credit card number',sanitiseMatched"
-
-

-verifyCPF

-

Description: Detects CPF numbers (Brazilian social number) in -input. This operator will first use the supplied regular expression to -perform an initial match, following up with an algorithm calculation to -minimize false positives. -

Example: -

-
# Detect CPF numbers in parameters and 
-# prevent them from being logged to audit log 
-SecRule ARGS "@verifyCPF /^([0-9]{3}\.){2}[0-9]{3}-[0-9]{2}$/" "phase:2,id:195,nolog,pass,msg:'Potential CPF number',sanitiseMatched"
-
-

-verifySSN

-

Description: Detects US social security numbers (SSN) in -input. This operator will first use the supplied regular expression to -perform an initial match, following up with an SSN algorithm calculation - to minimize false positives. -

Example: -

-
# Detect social security numbers in parameters and 
-# prevent them from being logged to audit log 
-SecRule ARGS "@verifySSN \d{3}-?\d{2}-?\d{4}" "phase:2,id:196,nolog,pass,msg:'Potential social security number',sanitiseMatched"
-
-

Version: 2.6 -

SSN Format: -

A Social Security number is broken up into 3 sections: -

-
  • Area (3 digits) -
  • Group (2 digits) -
  • Serial (4 digits) -
-

verifySSN checks: -

-
  • Must have 9 digits -
  • Cannot be a sequence number (ie,, 123456789, 012345678) -
  • Cannot be a repetition sequence number ( ie 11111111 , -222222222) -
  • Cannot have area and/or group and/or serial zeroed sequences -
  • Area code must be less than 740 -
  • Area code must be different then 666 -
-

within

-

Description: Returns true if the input value is found anywhere - within the parameter value (the opposite of @contains). Macro expansion - is performed on the parameter string before comparison. -

Example: -

-
# Detect request methods other than GET, POST and HEAD SecRule REQUEST_METHOD "!@within GET,POST,HEAD"
-
-

Macro Expansion

-

Macros allow for using place holders in rules that will be expanded -out to their values at runtime. Currently only variable expansion is -supported, however more options may be added in future versions of -ModSecurity. -

Format: -

-
%{VARIABLE}
-%{COLLECTION.VARIABLE}
-
-

Macro expansion can be used in actions such as initcol, setsid, -setuid, setvar, setenv, logdata. Operators that are evaluated at runtime - support expansion and are noted above. Such operators include -@beginsWith, @endsWith, @contains, @within and @streq. You cannot use -macro expansion for operators that are "compiled" such as @pm, @rx, etc. - as these operators have their values fixed at configure time for -efficiency. -

Some values you may want to expand include: TX, REMOTE_ADDR, -USERID, HIGHEST_SEVERITY, MATCHED_VAR, MATCHED_VAR_NAME, -MULTIPART_STRICT_ERROR, RULE, SESSION, USERID, among others. -

-

Persistant Storage

-

At this time it is only possible to havefive collections in which -data is stored persistantly (i.e. data available to multiple requests). -These are: GLOBAL, RESOURCE, IP, SESSION and USER. -

Every collection contains several built-in variables that are -available and are read-only unless otherwise specified: -

-
  1. CREATE_TIME - date/time of the creation of the -collection. -
  2. IS_NEW - set to 1 if the collection is new (not yet -persisted) otherwise set to 0. -
  3. KEY - the value of the initcol variable (the client's IP - address in the example). -
  4. LAST_UPDATE_TIME - date/time of the last update to the -collection. -
  5. TIMEOUT - date/time in seconds when the collection will -be updated on disk from memory (if no other updates occur). This -variable may be set if you wish to specifiy an explicit expiration time -(default is 3600 seconds). -
  6. UPDATE_COUNTER - how many times the collection has been -updated since creation. -
  7. UPDATE_RATE - is the average rate updates per minute -since creation. -
-

To create a collection to hold session variables (SESSION) use action - setsid. To create a collection to hold user variables (USER) use action - setuid. To create a collection to hold client address variables (IP), -global data or resource-specific data, use action initcol. -

-
Note 
Persistent collections can only be -initialized once per transaction. -
-
Note 
ModSecurity implements atomic updates of -persistent variables only for integer variables (counters) at this time. - Variables are read from storage whenever initcol is encountered in the -rules and persisted at the end of request processing. Counters are -adjusted by applying a delta generated by re-reading the persisted data -just before being persisted. This keeps counter data consistent even if -the counter was modified and persisted by another thread/process during -the transaction. -
-
Note 
ModSecurity uses a Berkley Database (SDBM) -for persistant storage. This type of database is generally limited to -storing a maximum of 1008 bytes per key. This may be a limitation if you - are attempting to store a considerable amount of data in variables for a - single key. Some of this limitation is planned to be reduced in a -future version of ModSecurity. -
-

Miscellaneous Topics

-

Impedance Mismatch

-

Web application firewalls have a difficult job trying to make sense -of data that passes by, without any knowledge of the application and its - business logic. The protection they provide comes from having an -independent layer of security on the outside. Because data validation is - done twice, security can be increased without having to touch the -application. In some cases, however, the fact that everything is done -twice brings problems. Problems can arise in the areas where the -communication protocols are not well specified, or where either the -device or the application do things that are not in the specification. -In such cases it may be possible to design payload that will be -interpreted in one way by one device and in another by the other device. - This problem is better known as Impedance Mismatch. It can be exploited - to evade the security devices. -

While we will continue to enhance ModSecurity to deal with -various evasion techniques the problem can only be minimized, but never -solved. With so many different application backend chances are some will - always do something completely unexpected. The only solution is to be -aware of the technologies in the backend when writing rules, adapting -the rules to remove the mismatch. See the next section for some -examples. -

-

- Impedance Mismatch with PHP Apps

-
  1. When writing rules to protect PHP applications you need to pay -attention to the following facts: -
  2. When "register_globals" is set to "On" request parameters are -automatically converted to script variables. In some PHP versions it is -even possible to override the $GLOBALS array. -
  3. Whitespace at the beginning of parameter names is ignored. -(This is very dangerous if you are writing rules to target specific -named variables.) -
  4. The remaining whitespace (in parameter names) is converted to -underscores. The same applies to dots and to a "[" if the variable name -does not contain a matching closing bracket. (Meaning that if you want -to exploit a script through a variable that contains an underscore in -the name you can send a parameter with a whitespace or a dot instead.) -
  5. Cookies can be treated as request parameters. -
  6. The discussion about variable names applies equally to the -cookie names. -
  7. The order in which parameters are taken from the request and -the environment is EGPCS (environment, GET, POST, Cookies, built-in -variables). This means that a POST parameter will overwrite the -parameters transported on the request line (in QUERY_STRING). -
  8. When "magic_quotes_gpc" is set to "On" PHP will use backslash -to escape the following characters: single quote, double quote, -backslash, and the nul byte. -
  9. If "magic_quotes_sybase" is set to "On" only the single quote -will be escaped using another single quote. In this case the -"magic_quotes_gpc" setting becomes irrelevant. The "magic_quotes_sybase" - setting completely overrides the "magic_quotes_gpc" behaviour but -"magic_quotes_gpc" still must be set to "On" for the Sybase-specific -quoting to be work. -
  10. PHP will also automatically create nested arrays for you. For -example "p[x][y]=1" results in a total of three variables. -
-

- A Recommended Base Configuration

-

The following is a recommended configuration file which handles the -main ModSecurity directives/setting. These are the items that the Admin - should handle and configure for their own site. These settings should -not be including within 3rd party rules files. -

-
# -- Rule engine initialization ----------------------------------------------
-
-# Enable ModSecurity, attaching it to every transaction. Use detection
-# only to start with, because that minimises the chances of post-installation
-# disruption.
-#
-SecRuleEngine DetectionOnly
-
-
-# -- Request body handling ---------------------------------------------------
-
-# Allow ModSecurity to access request bodies. If you don't, ModSecurity
-# won't be able to see any POST parameters, which opens a large security
-# hole for attackers to exploit.
-#
-SecRequestBodyAccess On
-
-
-# Enable XML request body parser.
-# Initiate XML Processor in case of xml content-type
-#
-SecRule REQUEST_HEADERS:Content-Type "text/xml" \
-     "phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
-
-
-# Maximum request body size we will accept for buffering. If you support
-# file uploads then the value given on the first line has to be as large
-# as the largest file you are willing to accept. The second value refers
-# to the size of data, with files excluded. You want to keep that value as
-# low as practical.
-#
-SecRequestBodyLimit 13107200
-SecRequestBodyNoFilesLimit 131072
-
-# Store up to 128 KB of request body data in memory. When the multipart
-# parser reachers this limit, it will start using your hard disk for
-# storage. That is slow, but unavoidable.
-#
-SecRequestBodyInMemoryLimit 131072
-
-# What do do if the request body size is above our configured limit.
-# Keep in mind that this setting will automatically be set to ProcessPartial
-# when SecRuleEngine is set to DetectionOnly mode in order to minimize
-# disruptions when initially deploying ModSecurity.
-#
-SecRequestBodyLimitAction Reject
-
-# Verify that we've correctly processed the request body.
-# As a rule of thumb, when failing to process a request body
-# you should reject the request (when deployed in blocking mode)
-# or log a high-severity alert (when deployed in detection-only mode).
-#
-SecRule REQBODY_ERROR "!@eq 0" \
-"phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2"
-
-# By default be strict with what we accept in the multipart/form-data
-# request body. If the rule below proves to be too strict for your
-# environment consider changing it to detection-only. You are encouraged
-# _not_ to remove it altogether.
-#
-SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
-"phase:2,t:none,log,deny,status:44,msg:'Multipart request body \
-failed strict validation: \
-PE %{REQBODY_PROCESSOR_ERROR}, \
-BQ %{MULTIPART_BOUNDARY_QUOTED}, \
-BW %{MULTIPART_BOUNDARY_WHITESPACE}, \
-DB %{MULTIPART_DATA_BEFORE}, \
-DA %{MULTIPART_DATA_AFTER}, \
-HF %{MULTIPART_HEADER_FOLDING}, \
-LF %{MULTIPART_LF_LINE}, \
-SM %{MULTIPART_MISSING_SEMICOLON}, \
-IQ %{MULTIPART_INVALID_QUOTING}, \
-IH %{MULTIPART_INVALID_HEADER_FOLDING}, \
-IH %{MULTIPART_FILE_LIMIT_EXCEEDED}'"
-
-# Did we see anything that might be a boundary?
-#
-SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \
-"phase:2,t:none,log,deny,status:44,msg:'Multipart parser detected a possible unmatched boundary.'"
-
-# PCRE Tuning
-# We want to avoid a potential RegEx DoS condition
-#
-SecPcreMatchLimit 1000
-SecPcreMatchLimitRecursion 1000
-
-# Some internal errors will set flags in TX and we will need to look for these.
-# All of these are prefixed with "MSC_".  The following flags currently exist:
-#
-# MSC_PCRE_LIMITS_EXCEEDED: PCRE match limits were exceeded.
-#
-SecRule TX:/^MSC_/ "!@streq 0" \
-        "phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'"
-
-
-# -- Response body handling --------------------------------------------------
-
-# Allow ModSecurity to access response bodies. 
-# You should have this directive enabled in order to identify errors
-# and data leakage issues.
-# 
-# Do keep in mind that enabling this directive does increases both
-# memory consumption and response latency.
-#
-SecResponseBodyAccess On
-
-# Which response MIME types do you want to inspect? You should adjust the
-# configuration below to catch documents but avoid static files
-# (e.g., images and archives).
-#
-SecResponseBodyMimeType text/plain text/html text/xml
-
-# Buffer response bodies of up to 512 KB in length.
-SecResponseBodyLimit 524288
-
-# What happens when we encounter a response body larger than the configured
-# limit? By default, we process what we have and let the rest through.
-# That's somewhat less secure, but does not break any legitimate pages.
-#
-SecResponseBodyLimitAction ProcessPartial
-
-
-# -- Filesystem configuration ------------------------------------------------
-
-# The location where ModSecurity stores temporary files (for example, when
-# it needs to handle a file upload that is larger than the configured limit).
-# 
-# This default setting is chosen due to all systems have /tmp available however, 
-# this is less than ideal. It is recommended that you specify a location that's private.
-#
-SecTmpDir /tmp/
-
-# The location where ModSecurity will keep its persistent data.  This default setting 
-# is chosen due to all systems have /tmp available however, it
-# too should be updated to a place that other users can't access.
-#
-SecDataDir /tmp/
-
-
-# -- File uploads handling configuration -------------------------------------
-
-# The location where ModSecurity stores intercepted uploaded files. This
-# location must be private to ModSecurity. You don't want other users on
-# the server to access the files, do you?
-#
-#SecUploadDir /opt/modsecurity/var/upload/
-
-# By default, only keep the files that were determined to be unusual
-# in some way (by an external inspection script). For this to work you
-# will also need at least one file inspection rule.
-#
-#SecUploadKeepFiles RelevantOnly
-
-# Uploaded files are by default created with permissions that do not allow
-# any other user to access them. You may need to relax that if you want to
-# interface ModSecurity to an external program (e.g., an anti-virus).
-#
-#SecUploadFileMode 0600
-
-
-# -- Debug log configuration -------------------------------------------------
-
-# The default debug log configuration is to duplicate the error, warning
-# and notice messages from the error log.
-#
-#SecDebugLog /opt/modsecurity/var/log/debug.log
-#SecDebugLogLevel 3
-
-
-# -- Audit log configuration -------------------------------------------------
-
-# Log the transactions that are marked by a rule, as well as those that
-# trigger a server error (determined by a 5xx or 4xx, excluding 404,  
-# level response status codes).
-#
-SecAuditEngine RelevantOnly
-SecAuditLogRelevantStatus "^(?:5|4(?!04))"
-
-# Log everything we know about a transaction.
-SecAuditLogParts ABIJDEFHKZ
-
-# Use a single file for logging. This is much easier to look at, but
-# assumes that you will use the audit log only ocassionally.
-#
-SecAuditLogType Serial
-SecAuditLog /var/log/modsec_audit.log
-
-# Specify the path for concurrent audit logging.
-#SecAuditLogStorageDir /opt/modsecurity/var/audit/
-
-
-# -- Miscellaneous -----------------------------------------------------------
-
-# Use the most commonly used application/x-www-form-urlencoded parameter
-# separator. There's probably only one application somewhere that uses
-# something else so don't expect to change this value.
-#
-SecArgumentSeparator &
-
-# Settle on version 0 (zero) cookies, as that is what most applications
-# use. Using an incorrect cookie version may open your installation to
-# evasion attacks (against the rules that examine named cookies).
-#
-SecCookieFormat 0
-
- - - - - - -
-
-
-
-
-
-
Views
- -
-
-
Personal tools
-
-
-
    -
-
-
- - - - - -
-
- -
- - - - - - - \ No newline at end of file diff --git a/doc/Reference_Manual_files/600px-Apache_request_cycle-modsecurity.jpg b/doc/Reference_Manual_files/600px-Apache_request_cycle-modsecurity.jpg deleted file mode 100644 index 6241c7252f..0000000000 Binary files a/doc/Reference_Manual_files/600px-Apache_request_cycle-modsecurity.jpg and /dev/null differ diff --git a/doc/Reference_Manual_files/ajax.js b/doc/Reference_Manual_files/ajax.js deleted file mode 100644 index afcfa70895..0000000000 --- a/doc/Reference_Manual_files/ajax.js +++ /dev/null @@ -1,167 +0,0 @@ -// remote scripting library -// (c) copyright 2005 modernmethod, inc -var sajax_debug_mode = false; -var sajax_request_type = "GET"; - -/** -* if sajax_debug_mode is true, this function outputs given the message into -* the element with id = sajax_debug; if no such element exists in the document, -* it is injected. -*/ -function sajax_debug(text) { - if (!sajax_debug_mode) return false; - - var e= document.getElementById('sajax_debug'); - - if (!e) { - e= document.createElement("p"); - e.className= 'sajax_debug'; - e.id= 'sajax_debug'; - - var b= document.getElementsByTagName("body")[0]; - - if (b.firstChild) b.insertBefore(e, b.firstChild); - else b.appendChild(e); - } - - var m= document.createElement("div"); - m.appendChild( document.createTextNode( text ) ); - - e.appendChild( m ); - - return true; -} - -/** -* compatibility wrapper for creating a new XMLHttpRequest object. -*/ -function sajax_init_object() { - sajax_debug("sajax_init_object() called..") - var A; - try { - // Try the new style before ActiveX so we don't - // unnecessarily trigger warnings in IE 7 when - // set to prompt about ActiveX usage - A = new XMLHttpRequest(); - } catch (e) { - try { - A=new ActiveXObject("Msxml2.XMLHTTP"); - } catch (e) { - try { - A=new ActiveXObject("Microsoft.XMLHTTP"); - } catch (oc) { - A=null; - } - } - } - if (!A) - sajax_debug("Could not create connection object."); - - return A; -} - -/** -* Perform an ajax call to mediawiki. Calls are handeled by AjaxDispatcher.php -* func_name - the name of the function to call. Must be registered in $wgAjaxExportList -* args - an array of arguments to that function -* target - the target that will handle the result of the call. If this is a function, -* if will be called with the XMLHttpRequest as a parameter; if it's an input -* element, its value will be set to the resultText; if it's another type of -* element, its innerHTML will be set to the resultText. -* -* Example: -* sajax_do_call('doFoo', [1, 2, 3], document.getElementById("showFoo")); -* -* This will call the doFoo function via MediaWiki's AjaxDispatcher, with -* (1, 2, 3) as the parameter list, and will show the result in the element -* with id = showFoo -*/ -function sajax_do_call(func_name, args, target) { - var i, x, n; - var uri; - var post_data; - uri = wgServer + - ((wgScript == null) ? (wgScriptPath + "/index.php") : wgScript) + - "?action=ajax"; - if (sajax_request_type == "GET") { - if (uri.indexOf("?") == -1) - uri = uri + "?rs=" + encodeURIComponent(func_name); - else - uri = uri + "&rs=" + encodeURIComponent(func_name); - for (i = 0; i < args.length; i++) - uri = uri + "&rsargs[]=" + encodeURIComponent(args[i]); - //uri = uri + "&rsrnd=" + new Date().getTime(); - post_data = null; - } else { - post_data = "rs=" + encodeURIComponent(func_name); - for (i = 0; i < args.length; i++) - post_data = post_data + "&rsargs[]=" + encodeURIComponent(args[i]); - } - x = sajax_init_object(); - if (!x) { - alert("AJAX not supported"); - return false; - } - - try { - x.open(sajax_request_type, uri, true); - } catch (e) { - if (window.location.hostname == "localhost") { - alert("Your browser blocks XMLHttpRequest to 'localhost', try using a real hostname for development/testing."); - } - throw e; - } - if (sajax_request_type == "POST") { - x.setRequestHeader("Method", "POST " + uri + " HTTP/1.1"); - x.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); - } - x.setRequestHeader("Pragma", "cache=yes"); - x.setRequestHeader("Cache-Control", "no-transform"); - x.onreadystatechange = function() { - if (x.readyState != 4) - return; - - sajax_debug("received (" + x.status + " " + x.statusText + ") " + x.responseText); - - //if (x.status != 200) - // alert("Error: " + x.status + " " + x.statusText + ": " + x.responseText); - //else - - if ( typeof( target ) == 'function' ) { - target( x ); - } - else if ( typeof( target ) == 'object' ) { - if ( target.tagName == 'INPUT' ) { - if (x.status == 200) target.value= x.responseText; - //else alert("Error: " + x.status + " " + x.statusText + " (" + x.responseText + ")"); - } - else { - if (x.status == 200) target.innerHTML = x.responseText; - else target.innerHTML= "
Error: " + x.status + " " + x.statusText + " (" + x.responseText + ")
"; - } - } - else { - alert("bad target for sajax_do_call: not a function or object: " + target); - } - - return; - } - - sajax_debug(func_name + " uri = " + uri + " / post = " + post_data); - x.send(post_data); - sajax_debug(func_name + " waiting.."); - delete x; - - return true; -} - -/** - * @return boolean whether the browser supports XMLHttpRequest - */ -function wfSupportsAjax() { - var request = sajax_init_object(); - var supportsAjax = request ? true : false; - delete request; - return supportsAjax; -} - diff --git a/doc/Reference_Manual_files/commonPrint.css b/doc/Reference_Manual_files/commonPrint.css deleted file mode 100644 index ecf146deef..0000000000 --- a/doc/Reference_Manual_files/commonPrint.css +++ /dev/null @@ -1,267 +0,0 @@ -/* -** MediaWiki Print style sheet for CSS2-capable browsers. -** Copyright Gabriel Wicke, http://www.aulinx.de/ -** -** Derived from the plone (http://plone.org/) styles -** Copyright Alexander Limi -*/ - -/* Thanks to A List Apart (http://alistapart.com/) for useful extras */ -a.stub, -a.new{ color:#ba0000; text-decoration:none; } - -#toc { - /*border:1px solid #2f6fab;*/ - border:1px solid #aaaaaa; - background-color:#f9f9f9; - padding:5px; -} -.tocindent { - margin-left: 2em; -} -.tocline { - margin-bottom: 0px; -} - -/* images */ -div.floatright { - float: right; - clear: right; - margin: 0; - position:relative; - border: 0.5em solid White; - border-width: 0.5em 0 0.8em 1.4em; -} -div.floatright p { font-style: italic;} -div.floatleft { - float: left; - margin: 0.3em 0.5em 0.5em 0; - position:relative; - border: 0.5em solid White; - border-width: 0.5em 1.4em 0.8em 0; -} -div.floatleft p { font-style: italic; } -/* thumbnails */ -div.thumb { - margin-bottom: 0.5em; - border-style: solid; border-color: White; - width: auto; - overflow: hidden; -} -div.thumb div { - border:1px solid #cccccc; - padding: 3px !important; - background-color:#f9f9f9; - font-size: 94%; - text-align: center; -} -div.thumb div a img { - border:1px solid #cccccc; -} -div.thumb div div.thumbcaption { - border: none; - padding: 0.3em 0 0.1em 0; -} -div.magnify { display: none; } -div.tright { - float: right; - clear: right; - border-width: 0.5em 0 0.8em 1.4em; -} -div.tleft { - float: left; - margin-right:0.5em; - border-width: 0.5em 1.4em 0.8em 0; -} -img.thumbborder { - border: 1px solid #dddddd; -} - -/* table standards */ -table.rimage { - float:right; - width:1pt; - position:relative; - margin-left:1em; - margin-bottom:1em; - text-align:center; -} - -body { - background: White; - /*font-size: 11pt !important;*/ - color: Black; - margin: 0; - padding: 0; -} - -.noprint, -div#jump-to-nav, -div.top, -div#column-one, -#colophon, -.editsection, -.toctoggle, -.tochidden, -div#f-poweredbyico, -div#f-copyrightico, -li#viewcount, -li#about, -li#disclaimer, -li#privacy { - /* Hides all the elements irrelevant for printing */ - display: none; -} - -ul { - list-style-type: square; -} - -#content { - background: none; - border: none ! important; - padding: 0 ! important; - margin: 0 ! important; -} -#footer { - background : white; - color : black; - border-top: 1px solid black; -} - -h1, h2, h3, h4, h5, h6 { - font-weight: bold; -} - -p, .documentDescription { - margin: 1em 0 ! important; - line-height: 1.2em; -} - -.tocindent p { - margin: 0 0 0 0 ! important; -} - -pre { - border: 1pt dashed black; - white-space: pre; - font-size: 8pt; - overflow: auto; - padding: 1em 0; - background : white; - color : black; -} - -table.listing, -table.listing td { - border: 1pt solid black; - border-collapse: collapse; -} - -a { - color: Black !important; - background: none !important; - padding: 0 !important; -} - -a:link, a:visited { - color: #520; - background: transparent; - text-decoration: underline; -} - -#content a.external.text:after, #content a.external.autonumber:after { - /* Expand URLs for printing */ - content: " (" attr(href) ") "; -} - -#globalWrapper { - width: 100% !important; - min-width: 0 !important; -} - -#content { - background : white; - color : black; -} - -#column-content { - margin: 0 !important; -} - -#column-content #content { - padding: 1em; - margin: 0 !important; -} -/* MSIE/Win doesn't understand 'inherit' */ -a, a.external, a.new, a.stub { - color: black ! important; - text-decoration: none ! important; -} - -/* Continue ... */ -a, a.external, a.new, a.stub { - color: inherit ! important; - text-decoration: inherit ! important; -} - -img { border: none; } -img.tex { vertical-align: middle; } -span.texhtml { font-family: serif; } - -#siteNotice { display: none; } - -table.gallery { - border: 1px solid #cccccc; - margin: 2px; - padding: 2px; - background-color:#ffffff; -} - -table.gallery tr { - vertical-align:top; -} - -div.gallerybox { - border: 1px solid #cccccc; - margin: 2px; - background-color:#f9f9f9; - width: 150px; -} - -div.gallerybox div.thumb { - text-align: center; - border: 1px solid #cccccc; - margin: 2px; -} - -div.gallerytext { - font-size: 94%; - padding: 2px 4px; -} - -/* -** Diff rendering -*/ -table.diff { background:white; } -td.diff-otitle { background:#ffffff; } -td.diff-ntitle { background:#ffffff; } -td.diff-addedline { - background:#ccffcc; - font-size: smaller; - border: solid 2px black; -} -td.diff-deletedline { - background:#ffffaa; - font-size: smaller; - border: dotted 2px black; -} -td.diff-context { - background:#eeeeee; - font-size: smaller; -} -.diffchange { - color: silver; - font-weight: bold; - text-decoration: underline; -} diff --git a/doc/Reference_Manual_files/index.css b/doc/Reference_Manual_files/index.css deleted file mode 100644 index aba5a86eaa..0000000000 --- a/doc/Reference_Manual_files/index.css +++ /dev/null @@ -1 +0,0 @@ -/* CSS placed here will affect the print output */ \ No newline at end of file diff --git a/doc/Reference_Manual_files/index.php b/doc/Reference_Manual_files/index.php deleted file mode 100644 index d4ddda0ed9..0000000000 --- a/doc/Reference_Manual_files/index.php +++ /dev/null @@ -1,8 +0,0 @@ -/* generated javascript */ -var skin = 'sourceforge'; -var stylepath = '/apps/mediawiki/mod-security/skins'; - -/* MediaWiki:Common.js */ -/* Any JavaScript here will be loaded for all users on every page load. */ - -/* MediaWiki:Sourceforge.js */ diff --git a/doc/Reference_Manual_files/index_002.css b/doc/Reference_Manual_files/index_002.css deleted file mode 100644 index f010367507..0000000000 --- a/doc/Reference_Manual_files/index_002.css +++ /dev/null @@ -1,2 +0,0 @@ -/* generated user stylesheet */ -a.new, #quickbar a.new { color: #CC2200; } diff --git a/doc/Reference_Manual_files/index_003.css b/doc/Reference_Manual_files/index_003.css deleted file mode 100644 index e034ba2a4b..0000000000 --- a/doc/Reference_Manual_files/index_003.css +++ /dev/null @@ -1 +0,0 @@ -/* CSS placed here will be applied to all skins */ \ No newline at end of file diff --git a/doc/Reference_Manual_files/index_004.css b/doc/Reference_Manual_files/index_004.css deleted file mode 100644 index c94e37366e..0000000000 --- a/doc/Reference_Manual_files/index_004.css +++ /dev/null @@ -1 +0,0 @@ -/* Empty */ \ No newline at end of file diff --git a/doc/Reference_Manual_files/poweredby_mediawiki_88x31.png b/doc/Reference_Manual_files/poweredby_mediawiki_88x31.png deleted file mode 100644 index ce1765d163..0000000000 Binary files a/doc/Reference_Manual_files/poweredby_mediawiki_88x31.png and /dev/null differ diff --git a/doc/Reference_Manual_files/wikibits.js b/doc/Reference_Manual_files/wikibits.js deleted file mode 100644 index 397dac9124..0000000000 --- a/doc/Reference_Manual_files/wikibits.js +++ /dev/null @@ -1,1000 +0,0 @@ -// MediaWiki JavaScript support functions - -var clientPC = navigator.userAgent.toLowerCase(); // Get client info -var is_gecko = /gecko/.test( clientPC ) && - !/khtml|spoofer|netscape\/7\.0/.test(clientPC); -var webkit_match = clientPC.match(/applewebkit\/(\d+)/); -if (webkit_match) { - var is_safari = clientPC.indexOf('applewebkit') != -1 && - clientPC.indexOf('spoofer') == -1; - var is_safari_win = is_safari && clientPC.indexOf('windows') != -1; - var webkit_version = parseInt(webkit_match[1]); -} -var is_khtml = navigator.vendor == 'KDE' || - ( document.childNodes && !document.all && !navigator.taintEnabled ); -// For accesskeys; note that FF3+ is included here! -var is_ff2 = /firefox\/[2-9]|minefield\/3/.test( clientPC ); -var is_ff2_ = /firefox\/2/.test( clientPC ); -// These aren't used here, but some custom scripts rely on them -var is_ff2_win = is_ff2 && clientPC.indexOf('windows') != -1; -var is_ff2_x11 = is_ff2 && clientPC.indexOf('x11') != -1; -if (clientPC.indexOf('opera') != -1) { - var is_opera = true; - var is_opera_preseven = window.opera && !document.childNodes; - var is_opera_seven = window.opera && document.childNodes; - var is_opera_95 = /opera\/(9.[5-9]|[1-9][0-9])/.test( clientPC ); -} - -// Global external objects used by this script. -/*extern ta, stylepath, skin */ - -// add any onload functions in this hook (please don't hard-code any events in the xhtml source) -var doneOnloadHook; - -if (!window.onloadFuncts) { - var onloadFuncts = []; -} - -function addOnloadHook(hookFunct) { - // Allows add-on scripts to add onload functions - if(!doneOnloadHook) { - onloadFuncts[onloadFuncts.length] = hookFunct; - } else { - hookFunct(); // bug in MSIE script loading - } -} - -function hookEvent(hookName, hookFunct) { - addHandler(window, hookName, hookFunct); -} - -function importScript(page) { - var uri = wgScript + '?title=' + - encodeURIComponent(page.replace(/ /g,'_')).replace('%2F','/').replace('%3A',':') + - '&action=raw&ctype=text/javascript'; - return importScriptURI(uri); -} - -var loadedScripts = {}; // included-scripts tracker -function importScriptURI(url) { - if (loadedScripts[url]) { - return null; - } - loadedScripts[url] = true; - var s = document.createElement('script'); - s.setAttribute('src',url); - s.setAttribute('type','text/javascript'); - document.getElementsByTagName('head')[0].appendChild(s); - return s; -} - -function importStylesheet(page) { - return importStylesheetURI(wgScript + '?action=raw&ctype=text/css&title=' + encodeURIComponent(page.replace(/ /g,'_'))); -} - -function importStylesheetURI(url) { - return document.createStyleSheet ? document.createStyleSheet(url) : appendCSS('@import "' + url + '";'); -} - -function appendCSS(text) { - var s = document.createElement('style'); - s.type = 'text/css'; - s.rel = 'stylesheet'; - if (s.styleSheet) s.styleSheet.cssText = text //IE - else s.appendChild(document.createTextNode(text + '')) //Safari sometimes borks on null - document.getElementsByTagName('head')[0].appendChild(s); - return s; -} - -// special stylesheet links -if (typeof stylepath != 'undefined' && typeof skin != 'undefined') { - if (is_opera_preseven) { - importStylesheetURI(stylepath+'/'+skin+'/Opera6Fixes.css'); - } else if (is_opera_seven && !is_opera_95) { - importStylesheetURI(stylepath+'/'+skin+'/Opera7Fixes.css'); - } else if (is_opera_95) { - importStylesheetURI(stylepath+'/'+skin+'/Opera9Fixes.css'); - } else if (is_khtml) { - importStylesheetURI(stylepath+'/'+skin+'/KHTMLFixes.css'); - } else if (is_ff2_) { - importStylesheetURI(stylepath+'/'+skin+'/FF2Fixes.css'); - } -} - -if (wgBreakFrames) { - // Un-trap us from framesets - if (window.top != window) { - window.top.location = window.location; - } -} - -function showTocToggle() { - if (document.createTextNode) { - // Uses DOM calls to avoid document.write + XHTML issues - - var linkHolder = document.getElementById('toctitle'); - if (!linkHolder) { - return; - } - - var outerSpan = document.createElement('span'); - outerSpan.className = 'toctoggle'; - - var toggleLink = document.createElement('a'); - toggleLink.id = 'togglelink'; - toggleLink.className = 'internal'; - toggleLink.href = 'javascript:toggleToc()'; - toggleLink.appendChild(document.createTextNode(tocHideText)); - - outerSpan.appendChild(document.createTextNode('[')); - outerSpan.appendChild(toggleLink); - outerSpan.appendChild(document.createTextNode(']')); - - linkHolder.appendChild(document.createTextNode(' ')); - linkHolder.appendChild(outerSpan); - - var cookiePos = document.cookie.indexOf("hidetoc="); - if (cookiePos > -1 && document.cookie.charAt(cookiePos + 8) == 1) { - toggleToc(); - } - } -} - -function changeText(el, newText) { - // Safari work around - if (el.innerText) { - el.innerText = newText; - } else if (el.firstChild && el.firstChild.nodeValue) { - el.firstChild.nodeValue = newText; - } -} - -function toggleToc() { - var toc = document.getElementById('toc').getElementsByTagName('ul')[0]; - var toggleLink = document.getElementById('togglelink'); - - if (toc && toggleLink && toc.style.display == 'none') { - changeText(toggleLink, tocHideText); - toc.style.display = 'block'; - document.cookie = "hidetoc=0"; - } else { - changeText(toggleLink, tocShowText); - toc.style.display = 'none'; - document.cookie = "hidetoc=1"; - } -} - -var mwEditButtons = []; -var mwCustomEditButtons = []; // eg to add in MediaWiki:Common.js - -function escapeQuotes(text) { - var re = new RegExp("'","g"); - text = text.replace(re,"\\'"); - re = new RegExp("\\n","g"); - text = text.replace(re,"\\n"); - return escapeQuotesHTML(text); -} - -function escapeQuotesHTML(text) { - var re = new RegExp('&',"g"); - text = text.replace(re,"&"); - re = new RegExp('"',"g"); - text = text.replace(re,"""); - re = new RegExp('<',"g"); - text = text.replace(re,"<"); - re = new RegExp('>',"g"); - text = text.replace(re,">"); - return text; -} - - -/** - * Set the accesskey prefix based on browser detection. - */ -var tooltipAccessKeyPrefix = 'alt-'; -if (is_opera) { - tooltipAccessKeyPrefix = 'shift-esc-'; -} else if (!is_safari_win && is_safari && webkit_version > 526) { - tooltipAccessKeyPrefix = 'ctrl-alt-'; -} else if (!is_safari_win && (is_safari - || clientPC.indexOf('mac') != -1 - || clientPC.indexOf('konqueror') != -1 )) { - tooltipAccessKeyPrefix = 'ctrl-'; -} else if (is_ff2) { - tooltipAccessKeyPrefix = 'alt-shift-'; -} -var tooltipAccessKeyRegexp = /\[(ctrl-)?(alt-)?(shift-)?(esc-)?(.)\]$/; - -/** - * Add the appropriate prefix to the accesskey shown in the tooltip. - * If the nodeList parameter is given, only those nodes are updated; - * otherwise, all the nodes that will probably have accesskeys by - * default are updated. - * - * @param Array nodeList -- list of elements to update - */ -function updateTooltipAccessKeys( nodeList ) { - if ( !nodeList ) { - // skins without a "column-one" element don't seem to have links with accesskeys either - var columnOne = document.getElementById("column-one"); - if ( columnOne ) - updateTooltipAccessKeys( columnOne.getElementsByTagName("a") ); - // these are rare enough that no such optimization is needed - updateTooltipAccessKeys( document.getElementsByTagName("input") ); - updateTooltipAccessKeys( document.getElementsByTagName("label") ); - return; - } - - for ( var i = 0; i < nodeList.length; i++ ) { - var element = nodeList[i]; - var tip = element.getAttribute("title"); - if ( tip && tooltipAccessKeyRegexp.exec(tip) ) { - tip = tip.replace(tooltipAccessKeyRegexp, - "["+tooltipAccessKeyPrefix+"$5]"); - element.setAttribute("title", tip ); - } - } -} - -/** - * Add a link to one of the portlet menus on the page, including: - * - * p-cactions: Content actions (shown as tabs above the main content in Monobook) - * p-personal: Personal tools (shown at the top right of the page in Monobook) - * p-navigation: Navigation - * p-tb: Toolbox - * - * This function exists for the convenience of custom JS authors. All - * but the first three parameters are optional, though providing at - * least an id and a tooltip is recommended. - * - * By default the new link will be added to the end of the list. To - * add the link before a given existing item, pass the DOM node of - * that item (easily obtained with document.getElementById()) as the - * nextnode parameter; to add the link _after_ an existing item, pass - * the node's nextSibling instead. - * - * @param String portlet -- id of the target portlet ("p-cactions", "p-personal", "p-navigation" or "p-tb") - * @param String href -- link URL - * @param String text -- link text (will be automatically lowercased by CSS for p-cactions in Monobook) - * @param String id -- id of the new item, should be unique and preferably have the appropriate prefix ("ca-", "pt-", "n-" or "t-") - * @param String tooltip -- text to show when hovering over the link, without accesskey suffix - * @param String accesskey -- accesskey to activate this link (one character, try to avoid conflicts) - * @param Node nextnode -- the DOM node before which the new item should be added, should be another item in the same list - * - * @return Node -- the DOM node of the new item (an LI element) or null - */ -function addPortletLink(portlet, href, text, id, tooltip, accesskey, nextnode) { - var node = document.getElementById(portlet); - if ( !node ) return null; - node = node.getElementsByTagName( "ul" )[0]; - if ( !node ) return null; - - var link = document.createElement( "a" ); - link.appendChild( document.createTextNode( text ) ); - link.href = href; - - var item = document.createElement( "li" ); - item.appendChild( link ); - if ( id ) item.id = id; - - if ( accesskey ) { - link.setAttribute( "accesskey", accesskey ); - tooltip += " ["+accesskey+"]"; - } - if ( tooltip ) { - link.setAttribute( "title", tooltip ); - } - if ( accesskey && tooltip ) { - updateTooltipAccessKeys( new Array( link ) ); - } - - if ( nextnode && nextnode.parentNode == node ) - node.insertBefore( item, nextnode ); - else - node.appendChild( item ); // IE compatibility (?) - - return item; -} - -function getInnerText(el) { - if (typeof el == "string") return el; - if (typeof el == "undefined") { return el }; - if (el.textContent) return el.textContent; // not needed but it is faster - if (el.innerText) return el.innerText; // IE doesn't have textContent - var str = ""; - - var cs = el.childNodes; - var l = cs.length; - for (var i = 0; i < l; i++) { - switch (cs[i].nodeType) { - case 1: //ELEMENT_NODE - str += ts_getInnerText(cs[i]); - break; - case 3: //TEXT_NODE - str += cs[i].nodeValue; - break; - } - } - return str; -} - - -/** - * Set up accesskeys/tooltips from the deprecated ta array. If doId - * is specified, only set up for that id. Note that this function is - * deprecated and will not be supported indefinitely -- use - * updateTooltipAccessKey() instead. - * - * @param mixed doId string or null - */ -function akeytt( doId ) { - // A lot of user scripts (and some of the code below) break if - // ta isn't defined, so we make sure it is. Explictly using - // window.ta avoids a "ta is not defined" error. - if (!window.ta) window.ta = new Array; - - // Make a local, possibly restricted, copy to avoid clobbering - // the original. - var ta; - if ( doId ) { - ta = [doId]; - } else { - ta = window.ta; - } - - // Now deal with evil deprecated ta - var watchCheckboxExists = document.getElementById( 'wpWatchthis' ) ? true : false; - for (var id in ta) { - var n = document.getElementById(id); - if (n) { - var a = null; - var ak = ''; - // Are we putting accesskey in it - if (ta[id][0].length > 0) { - // Is this object a object? If not assume it's the next child. - - if (n.nodeName.toLowerCase() == "a") { - a = n; - } else { - a = n.childNodes[0]; - } - // Don't add an accesskey for the watch tab if the watch - // checkbox is also available. - if (a && ((id != 'ca-watch' && id != 'ca-unwatch') || !watchCheckboxExists)) { - a.accessKey = ta[id][0]; - ak = ' ['+tooltipAccessKeyPrefix+ta[id][0]+']'; - } - } else { - // We don't care what type the object is when assigning tooltip - a = n; - ak = ''; - } - - if (a) { - a.title = ta[id][1]+ak; - } - } - } -} - -var checkboxes; -var lastCheckbox; - -function setupCheckboxShiftClick() { - checkboxes = []; - lastCheckbox = null; - var inputs = document.getElementsByTagName('input'); - addCheckboxClickHandlers(inputs); -} - -function addCheckboxClickHandlers(inputs, start) { - if ( !start) start = 0; - - var finish = start + 250; - if ( finish > inputs.length ) - finish = inputs.length; - - for ( var i = start; i < finish; i++ ) { - var cb = inputs[i]; - if ( !cb.type || cb.type.toLowerCase() != 'checkbox' ) - continue; - var end = checkboxes.length; - checkboxes[end] = cb; - cb.index = end; - cb.onclick = checkboxClickHandler; - } - - if ( finish < inputs.length ) { - setTimeout( function () { - addCheckboxClickHandlers(inputs, finish); - }, 200 ); - } -} - -function checkboxClickHandler(e) { - if (typeof e == 'undefined') { - e = window.event; - } - if ( !e.shiftKey || lastCheckbox === null ) { - lastCheckbox = this.index; - return true; - } - var endState = this.checked; - var start, finish; - if ( this.index < lastCheckbox ) { - start = this.index + 1; - finish = lastCheckbox; - } else { - start = lastCheckbox; - finish = this.index - 1; - } - for (var i = start; i <= finish; ++i ) { - checkboxes[i].checked = endState; - } - lastCheckbox = this.index; - return true; -} - -function toggle_element_activation(ida,idb) { - if (!document.getElementById) { - return; - } - document.getElementById(ida).disabled=true; - document.getElementById(idb).disabled=false; -} - -function toggle_element_check(ida,idb) { - if (!document.getElementById) { - return; - } - document.getElementById(ida).checked=true; - document.getElementById(idb).checked=false; -} - -/* - Written by Jonathan Snook, http://www.snook.ca/jonathan - Add-ons by Robert Nyman, http://www.robertnyman.com - Author says "The credit comment is all it takes, no license. Go crazy with it!:-)" - From http://www.robertnyman.com/2005/11/07/the-ultimate-getelementsbyclassname/ -*/ -function getElementsByClassName(oElm, strTagName, oClassNames){ - var arrReturnElements = new Array(); - if ( typeof( oElm.getElementsByClassName ) == "function" ) { - /* Use a native implementation where possible FF3, Saf3.2, Opera 9.5 */ - var arrNativeReturn = oElm.getElementsByClassName( oClassNames ); - if ( strTagName == "*" ) - return arrNativeReturn; - for ( var h=0; h < arrNativeReturn.length; h++ ) { - if( arrNativeReturn[h].tagName.toLowerCase() == strTagName.toLowerCase() ) - arrReturnElements[arrReturnElements.length] = arrNativeReturn[h]; - } - return arrReturnElements; - } - var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName); - var arrRegExpClassNames = new Array(); - if(typeof oClassNames == "object"){ - for(var i=0; i 0) { - if (table.tHead && table.tHead.rows.length > 0) { - firstRow = table.tHead.rows[table.tHead.rows.length-1]; - } else { - firstRow = table.rows[0]; - } - } - if (!firstRow) return; - - // We have a first row: assume it's the header, and make its contents clickable links - for (var i = 0; i < firstRow.cells.length; i++) { - var cell = firstRow.cells[i]; - if ((" "+cell.className+" ").indexOf(" unsortable ") == -1) { - cell.innerHTML += '  ' - + '' - + '' - + '↓'; - } - } - if (ts_alternate_row_colors) { - ts_alternate(table); - } -} - -function ts_getInnerText(el) { - return getInnerText( el ); -} - -function ts_resortTable(lnk) { - // get the span - var span = lnk.getElementsByTagName('span')[0]; - - var td = lnk.parentNode; - var tr = td.parentNode; - var column = td.cellIndex; - - var table = tr.parentNode; - while (table && !(table.tagName && table.tagName.toLowerCase() == 'table')) - table = table.parentNode; - if (!table) return; - - if (table.rows.length <= 1) return; - - // Generate the number transform table if it's not done already - if (ts_number_transform_table == null) { - ts_initTransformTable(); - } - - // Work out a type for the column - // Skip the first row if that's where the headings are - var rowStart = (table.tHead && table.tHead.rows.length > 0 ? 0 : 1); - - var itm = ""; - for (var i = rowStart; i < table.rows.length; i++) { - if (table.rows[i].cells.length > column) { - itm = ts_getInnerText(table.rows[i].cells[column]); - itm = itm.replace(/^[\s\xa0]+/, "").replace(/[\s\xa0]+$/, ""); - if (itm != "") break; - } - } - - // TODO: bug 8226, localised date formats - var sortfn = ts_sort_generic; - var preprocessor = ts_toLowerCase; - if (/^\d\d[\/. -][a-zA-Z]{3}[\/. -]\d\d\d\d$/.test(itm)) { - preprocessor = ts_dateToSortKey; - } else if (/^\d\d[\/.-]\d\d[\/.-]\d\d\d\d$/.test(itm)) { - preprocessor = ts_dateToSortKey; - } else if (/^\d\d[\/.-]\d\d[\/.-]\d\d$/.test(itm)) { - preprocessor = ts_dateToSortKey; - // pound dollar euro yen currency cents - } else if (/(^[\u00a3$\u20ac\u00a4\u00a5]|\u00a2$)/.test(itm)) { - preprocessor = ts_currencyToSortKey; - } else if (ts_number_regex.test(itm)) { - preprocessor = ts_parseFloat; - } - - var reverse = (span.getAttribute("sortdir") == 'down'); - - var newRows = new Array(); - var staticRows = new Array(); - for (var j = rowStart; j < table.rows.length; j++) { - var row = table.rows[j]; - if((" "+row.className+" ").indexOf(" unsortable ") < 0) { - var keyText = ts_getInnerText(row.cells[column]); - var oldIndex = (reverse ? -j : j); - var preprocessed = preprocessor( keyText ); - - newRows[newRows.length] = new Array(row, preprocessed, oldIndex); - } else staticRows[staticRows.length] = new Array(row, false, j-rowStart); - } - - newRows.sort(sortfn); - - var arrowHTML; - if (reverse) { - arrowHTML = '↓'; - newRows.reverse(); - span.setAttribute('sortdir','up'); - } else { - arrowHTML = '↑'; - span.setAttribute('sortdir','down'); - } - - for (var i = 0; i < staticRows.length; i++) { - var row = staticRows[i]; - newRows.splice(row[2], 0, row); - } - - // We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones - // don't do sortbottom rows - for (var i = 0; i < newRows.length; i++) { - if ((" "+newRows[i][0].className+" ").indexOf(" sortbottom ") == -1) - table.tBodies[0].appendChild(newRows[i][0]); - } - // do sortbottom rows only - for (var i = 0; i < newRows.length; i++) { - if ((" "+newRows[i][0].className+" ").indexOf(" sortbottom ") != -1) - table.tBodies[0].appendChild(newRows[i][0]); - } - - // Delete any other arrows there may be showing - var spans = getElementsByClassName(tr, "span", "sortarrow"); - for (var i = 0; i < spans.length; i++) { - spans[i].innerHTML = '↓'; - } - span.innerHTML = arrowHTML; - - if (ts_alternate_row_colors) { - ts_alternate(table); - } -} - -function ts_initTransformTable() { - if ( typeof wgSeparatorTransformTable == "undefined" - || ( wgSeparatorTransformTable[0] == '' && wgDigitTransformTable[2] == '' ) ) - { - digitClass = "[0-9,.]"; - ts_number_transform_table = false; - } else { - ts_number_transform_table = {}; - // Unpack the transform table - // Separators - ascii = wgSeparatorTransformTable[0].split("\t"); - localised = wgSeparatorTransformTable[1].split("\t"); - for ( var i = 0; i < ascii.length; i++ ) { - ts_number_transform_table[localised[i]] = ascii[i]; - } - // Digits - ascii = wgDigitTransformTable[0].split("\t"); - localised = wgDigitTransformTable[1].split("\t"); - for ( var i = 0; i < ascii.length; i++ ) { - ts_number_transform_table[localised[i]] = ascii[i]; - } - - // Construct regex for number identification - digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ',', '\\.']; - maxDigitLength = 1; - for ( var digit in ts_number_transform_table ) { - // Escape regex metacharacters - digits.push( - digit.replace( /[\\\\$\*\+\?\.\(\)\|\{\}\[\]\-]/, - function( s ) { return '\\' + s; } ) - ); - if (digit.length > maxDigitLength) { - maxDigitLength = digit.length; - } - } - if ( maxDigitLength > 1 ) { - digitClass = '[' + digits.join( '', digits ) + ']'; - } else { - digitClass = '(' + digits.join( '|', digits ) + ')'; - } - } - - // We allow a trailing percent sign, which we just strip. This works fine - // if percents and regular numbers aren't being mixed. - ts_number_regex = new RegExp( - "^(" + - "[+-]?[0-9][0-9,]*(\\.[0-9,]*)?(E[+-]?[0-9][0-9,]*)?" + // Fortran-style scientific - "|" + - "[+-]?" + digitClass + "+%?" + // Generic localised - ")$", "i" - ); -} - -function ts_toLowerCase( s ) { - return s.toLowerCase(); -} - -function ts_dateToSortKey(date) { - // y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX - if (date.length == 11) { - switch (date.substr(3,3).toLowerCase()) { - case "jan": var month = "01"; break; - case "feb": var month = "02"; break; - case "mar": var month = "03"; break; - case "apr": var month = "04"; break; - case "may": var month = "05"; break; - case "jun": var month = "06"; break; - case "jul": var month = "07"; break; - case "aug": var month = "08"; break; - case "sep": var month = "09"; break; - case "oct": var month = "10"; break; - case "nov": var month = "11"; break; - case "dec": var month = "12"; break; - // default: var month = "00"; - } - return date.substr(7,4)+month+date.substr(0,2); - } else if (date.length == 10) { - if (ts_europeandate == false) { - return date.substr(6,4)+date.substr(0,2)+date.substr(3,2); - } else { - return date.substr(6,4)+date.substr(3,2)+date.substr(0,2); - } - } else if (date.length == 8) { - yr = date.substr(6,2); - if (parseInt(yr) < 50) { - yr = '20'+yr; - } else { - yr = '19'+yr; - } - if (ts_europeandate == true) { - return yr+date.substr(3,2)+date.substr(0,2); - } else { - return yr+date.substr(0,2)+date.substr(3,2); - } - } - return "00000000"; -} - -function ts_parseFloat( s ) { - if ( !s ) { - return 0; - } - if (ts_number_transform_table != false) { - var newNum = '', c; - - for ( var p = 0; p < s.length; p++ ) { - c = s.charAt( p ); - if (c in ts_number_transform_table) { - newNum += ts_number_transform_table[c]; - } else { - newNum += c; - } - } - s = newNum; - } - - num = parseFloat(s.replace(/,/g, "")); - return (isNaN(num) ? 0 : num); -} - -function ts_currencyToSortKey( s ) { - return ts_parseFloat(s.replace(/[^0-9.,]/g,'')); -} - -function ts_sort_generic(a, b) { - return a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : a[2] - b[2]; -} - -function ts_alternate(table) { - // Take object table and get all it's tbodies. - var tableBodies = table.getElementsByTagName("tbody"); - // Loop through these tbodies - for (var i = 0; i < tableBodies.length; i++) { - // Take the tbody, and get all it's rows - var tableRows = tableBodies[i].getElementsByTagName("tr"); - // Loop through these rows - // Start at 1 because we want to leave the heading row untouched - for (var j = 0; j < tableRows.length; j++) { - // Check if j is even, and apply classes for both possible results - var oldClasses = tableRows[j].className.split(" "); - var newClassName = ""; - for (var k = 0; k < oldClasses.length; k++) { - if (oldClasses[k] != "" && oldClasses[k] != "even" && oldClasses[k] != "odd") - newClassName += oldClasses[k] + " "; - } - tableRows[j].className = newClassName + (j % 2 == 0 ? "even" : "odd"); - } - } -} - -/* - * End of table sorting code - */ - - -/** - * Add a cute little box at the top of the screen to inform the user of - * something, replacing any preexisting message. - * - * @param String -or- Dom Object message HTML to be put inside the right div - * @param String className Used in adding a class; should be different for each - * call to allow CSS/JS to hide different boxes. null = no class used. - * @return Boolean True on success, false on failure - */ -function jsMsg( message, className ) { - if ( !document.getElementById ) { - return false; - } - // We special-case skin structures provided by the software. Skins that - // choose to abandon or significantly modify our formatting can just define - // an mw-js-message div to start with. - var messageDiv = document.getElementById( 'mw-js-message' ); - if ( !messageDiv ) { - messageDiv = document.createElement( 'div' ); - if ( document.getElementById( 'column-content' ) - && document.getElementById( 'content' ) ) { - // MonoBook, presumably - document.getElementById( 'content' ).insertBefore( - messageDiv, - document.getElementById( 'content' ).firstChild - ); - } else if ( document.getElementById('content') - && document.getElementById( 'article' ) ) { - // Non-Monobook but still recognizable (old-style) - document.getElementById( 'article').insertBefore( - messageDiv, - document.getElementById( 'article' ).firstChild - ); - } else { - return false; - } - } - - messageDiv.setAttribute( 'id', 'mw-js-message' ); - messageDiv.style.display = 'block'; - if( className ) { - messageDiv.setAttribute( 'class', 'mw-js-message-'+className ); - } - - if (typeof message === 'object') { - while (messageDiv.hasChildNodes()) // Remove old content - messageDiv.removeChild(messageDiv.firstChild); - messageDiv.appendChild (message); // Append new content - } - else { - messageDiv.innerHTML = message; - } - return true; -} - -/** - * Inject a cute little progress spinner after the specified element - * - * @param element Element to inject after - * @param id Identifier string (for use with removeSpinner(), below) - */ -function injectSpinner( element, id ) { - var spinner = document.createElement( "img" ); - spinner.id = "mw-spinner-" + id; - spinner.src = stylepath + "/common/images/spinner.gif"; - spinner.alt = spinner.title = "..."; - if( element.nextSibling ) { - element.parentNode.insertBefore( spinner, element.nextSibling ); - } else { - element.parentNode.appendChild( spinner ); - } -} - -/** - * Remove a progress spinner added with injectSpinner() - * - * @param id Identifier string - */ -function removeSpinner( id ) { - var spinner = document.getElementById( "mw-spinner-" + id ); - if( spinner ) { - spinner.parentNode.removeChild( spinner ); - } -} - -function runOnloadHook() { - // don't run anything below this for non-dom browsers - if (doneOnloadHook || !(document.getElementById && document.getElementsByTagName)) { - return; - } - - // set this before running any hooks, since any errors below - // might cause the function to terminate prematurely - doneOnloadHook = true; - - updateTooltipAccessKeys( null ); - akeytt( null ); - setupCheckboxShiftClick(); - sortables_init(); - - // Run any added-on functions - for (var i = 0; i < onloadFuncts.length; i++) { - onloadFuncts[i](); - } -} - -/** - * Add an event handler to an element - * - * @param Element element Element to add handler to - * @param String attach Event to attach to - * @param callable handler Event handler callback - */ -function addHandler( element, attach, handler ) { - if( window.addEventListener ) { - element.addEventListener( attach, handler, false ); - } else if( window.attachEvent ) { - element.attachEvent( 'on' + attach, handler ); - } -} - -/** - * Add a click event handler to an element - * - * @param Element element Element to add handler to - * @param callable handler Event handler callback - */ -function addClickHandler( element, handler ) { - addHandler( element, 'click', handler ); -} - -/** - * Removes an event handler from an element - * - * @param Element element Element to remove handler from - * @param String remove Event to remove - * @param callable handler Event handler callback to remove - */ -function removeHandler( element, remove, handler ) { - if( window.removeEventListener ) { - element.removeEventListener( remove, handler, false ); - } else if( window.detachEvent ) { - element.detachEvent( 'on' + remove, handler ); - } -} -//note: all skins should call runOnloadHook() at the end of html output, -// so the below should be redundant. It's there just in case. -hookEvent("load", runOnloadHook); diff --git a/nginx/TODO b/nginx/TODO index fb443444ea..a8d9925798 100644 --- a/nginx/TODO +++ b/nginx/TODO @@ -13,3 +13,5 @@ Modsecurity NGINX TODO * Source code documentation (insert doxygen headers) * Create better build infrastructure with support for tests and automated regression + +* Better things for test diff --git a/tests/msc_test.c b/tests/msc_test.c index 6200d78db7..f6637f506a 100644 --- a/tests/msc_test.c +++ b/tests/msc_test.c @@ -79,7 +79,7 @@ unsigned long int DSOLOCAL msc_pcre_match_limit = 0; unsigned long int DSOLOCAL msc_pcre_match_limit_recursion = 0; /* Stubs */ -char *format_error_log_message(apr_pool_t *mp, error_message *em) { +char *format_error_log_message(apr_pool_t *mp, error_message_t *em) { return "FAKE ERROR LOG MESSAGE"; }