Added m.getvars() and finalised Lua support.

This commit is contained in:
ivanr 2007-12-21 12:50:03 +00:00
parent 8924f605d4
commit 2068357af8
9 changed files with 322 additions and 135 deletions

View File

@ -1,9 +1,14 @@
20 Dec 2007 - 2.5.0-rc1 21 Dec 2007 - 2.5.0-rc1
----------------------- -----------------------
Changes since 2.5.0-dev2: Changes since 2.5.0-dev2:
* Added support for Lua scripting in the following ways: SecRuleScript
can be used to specify a script to execute as a rule, the exec
action processes Lua scripts internally, and does the @inspectFile
operator. Refer to the documentation for more details.
* Updated included Core Ruleset to version 1.5.1. * Updated included Core Ruleset to version 1.5.1.
* Changed how allow works. Used on its own it now allows phases 1-4. Used * Changed how allow works. Used on its own it now allows phases 1-4. Used

View File

@ -39,8 +39,6 @@ APACHECTL = apachectl
INCLUDES = -I /usr/include/libxml2 -I /usr/include/lua5.1 INCLUDES = -I /usr/include/libxml2 -I /usr/include/lua5.1
# INCLUDES = -I /usr/include/libxml2 -I /path/to/httpd-x.y/srclib/pcre # INCLUDES = -I /usr/include/libxml2 -I /path/to/httpd-x.y/srclib/pcre
DEFS = -DWITH_LUA
# DEFS = -DWITH_ICONV
# DEFS = -DPERFORMANCE_MEASUREMENT # DEFS = -DPERFORMANCE_MEASUREMENT
# DEFS = -DNO_MODSEC_API # DEFS = -DNO_MODSEC_API
# DEFS = -DDEBUG_CONF # DEFS = -DDEBUG_CONF

View File

@ -1283,14 +1283,12 @@ static const char *cmd_rule_inheritance(cmd_parms *cmd, void *_dcfg, int flag) {
return NULL; return NULL;
} }
#ifdef WITH_LUA
static const char *cmd_rule_script(cmd_parms *cmd, void *_dcfg, const char *p1, static const char *cmd_rule_script(cmd_parms *cmd, void *_dcfg, const char *p1,
const char *p2) const char *p2)
{ {
const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1); const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1);
return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_LUA, filename, p2, NULL); return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_LUA, filename, p2, NULL);
} }
#endif
static const char *cmd_rule_remove_by_id(cmd_parms *cmd, void *_dcfg, const char *p1) { static const char *cmd_rule_remove_by_id(cmd_parms *cmd, void *_dcfg, const char *p1) {
directory_config *dcfg = (directory_config *)_dcfg; directory_config *dcfg = (directory_config *)_dcfg;
@ -1887,7 +1885,6 @@ const command_rec module_directives[] = {
"On or Off" "On or Off"
), ),
#ifdef WITH_LUA
AP_INIT_TAKE12 ( AP_INIT_TAKE12 (
"SecRuleScript", "SecRuleScript",
cmd_rule_script, cmd_rule_script,
@ -1895,7 +1892,6 @@ const command_rec module_directives[] = {
CMD_SCOPE_ANY, CMD_SCOPE_ANY,
"" // TODO "" // TODO
), ),
#endif
AP_INIT_ITERATE ( AP_INIT_ITERATE (
"SecRuleRemoveById", "SecRuleRemoveById",

View File

@ -1,9 +1,6 @@
#include "msc_lua.h" #include "msc_lua.h"
#ifdef WITH_LUA
#include "apr_strings.h" #include "apr_strings.h"
typedef struct { typedef struct {
@ -123,18 +120,60 @@ static int l_log(lua_State *L) {
return 0; return 0;
} }
/**
*
*/
static apr_array_header_t *resolve_tfns(lua_State *L, int idx, modsec_rec *msr, apr_pool_t *mp) {
apr_array_header_t *tfn_arr = NULL;
msre_tfn_metadata *tfn = NULL;
char *name = NULL;
tfn_arr = apr_array_make(mp, 25, sizeof(msre_tfn_metadata *));
if (tfn_arr == NULL) return NULL;
if (lua_istable(L, idx)) { /* Is the second parameter an array? */
int i, n = lua_objlen(L, idx);
for(i = 1; i <= n; i++) {
lua_rawgeti(L, idx, i);
name = (char *)luaL_checkstring(L, -1);
tfn = msre_engine_tfn_resolve(msr->modsecurity->msre, name);
if (tfn == NULL) {
msr_log(msr, 1, "SecRuleScript: Invalid transformation function: %s", name);
} else {
*(msre_tfn_metadata **)apr_array_push(tfn_arr) = tfn;
}
}
} else if (lua_isstring(L, idx)) { /* The second parameter may be a simple string? */
name = (char *)luaL_checkstring(L, idx);
tfn = msre_engine_tfn_resolve(msr->modsecurity->msre, name);
if (tfn == NULL) {
msr_log(msr, 1, "SecRuleScript: Invalid transformation function: %s", name);
} else {
*(msre_tfn_metadata **)apr_array_push(tfn_arr) = tfn;
}
} else {
// TODO Error
return NULL;
}
return tfn_arr;
}
/** /**
* *
*/ */
static int l_getvar(lua_State *L) { static int l_getvar(lua_State *L) {
char *varname = NULL; char *varname = NULL, *param = NULL;
char *param = NULL;
modsec_rec *msr = NULL; modsec_rec *msr = NULL;
msre_rule *rule = NULL; msre_rule *rule = NULL;
char *my_error_msg = NULL; char *my_error_msg = NULL;
char *p1 = NULL;
apr_array_header_t *tfn_arr = NULL;
msre_var *vx = NULL;
/* Retrieve parameters. */ /* Retrieve parameters. */
varname = (char *)luaL_checkstring(L, 1); p1 = (char *)luaL_checkstring(L, 1);
/* Retrieve msr. */ /* Retrieve msr. */
lua_getglobal(L, "__msr"); lua_getglobal(L, "__msr");
@ -144,100 +183,123 @@ static int l_getvar(lua_State *L) {
lua_getglobal(L, "__rule"); lua_getglobal(L, "__rule");
rule = (msre_rule *)lua_topointer(L, -1); rule = (msre_rule *)lua_topointer(L, -1);
/* Resolve variable $varname. */ /* Extract the variable name and its parameter from the script. */
varname = apr_pstrdup(msr->msc_rule_mptmp, p1);
param = strchr(varname, '.'); param = strchr(varname, '.');
if (param != NULL) { if (param != NULL) {
*param = '\0'; *param = '\0';
param++; param++;
} }
/* Resolve variable. */
msre_var *var = msre_create_var_ex(msr->msc_rule_mptmp, msr->modsecurity->msre, msre_var *var = msre_create_var_ex(msr->msc_rule_mptmp, msr->modsecurity->msre,
varname, param, msr, &my_error_msg); varname, param, msr, &my_error_msg);
if (var == NULL) { if (var == NULL) {
msr_log(msr, 1, "SecRuleScript: Failed to resolve variable: %s", varname); msr_log(msr, 1, "%s", my_error_msg);
lua_pushnil(L);
return 0; return 0;
} else {
msre_var *vx = NULL;
vx = generate_single_var(msr, var, rule, msr->msc_rule_mptmp);
if (vx != NULL) {
char *rval = NULL;
long int rval_len = -1;
/* Transform the variable if a list of transformation
* functions has been supplied.
*/
if (lua_istable(L, 2)) { /* Is the second parameter an array? */
int i, n = lua_objlen(L, 2);
/* Make a copy so that we don't ruin the original value. */
vx->value = apr_pstrmemdup(msr->msc_rule_mptmp, vx->value, vx->value_len);
for(i = 1; i <= n; i++) {
msre_tfn_metadata *tfn = NULL;
char *name = NULL;
int rc = 0;
lua_rawgeti(L, 2, i);
name = (char *)luaL_checkstring(L, -1);
tfn = msre_engine_tfn_resolve(msr->modsecurity->msre, name);
if (tfn == NULL) {
msr_log(msr, 1, "SecRuleScript: Invalid transformation function in getvar() call: %s", name);
return 0;
}
rc = tfn->execute(msr->msc_rule_mptmp, (unsigned char*)vx->value,
vx->value_len, &rval, &rval_len);
vx->value = rval;
vx->value_len = rval_len;
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "T (%d) %s: \"%s\"", rc, tfn->name,
log_escape_nq_ex(msr->msc_rule_mptmp, vx->value, vx->value_len));
}
}
}
else if (lua_isstring(L, 2)) { /* The second parameter may be a simple string? */
msre_tfn_metadata *tfn = NULL;
char *name = NULL;
int rc = 0;
/* Make a copy so that we don't ruin the original value. */
vx->value = apr_pstrmemdup(msr->msc_rule_mptmp, vx->value, vx->value_len);
name = (char *)luaL_checkstring(L, 2);
tfn = msre_engine_tfn_resolve(msr->modsecurity->msre, name);
if (tfn == NULL) {
msr_log(msr, 1, "SecRuleScript: Invalid transformation function in getvar() call: %s", name);
return 0;
}
rc = tfn->execute(msr->msc_rule_mptmp, (unsigned char *)vx->value,
vx->value_len, &rval, &rval_len);
vx->value = rval;
vx->value_len = rval_len;
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "T (%d) %s: \"%s\"", rc, tfn->name,
log_escape_nq_ex(msr->msc_rule_mptmp, vx->value, vx->value_len));
}
}
lua_pushlstring(L, vx->value, vx->value_len);
return 1;
}
} }
return 0; /* Resolve transformation functions. */
tfn_arr = resolve_tfns(L, 2, msr, msr->msc_rule_mptmp);
/* Generate variable. */
vx = generate_single_var(msr, var, tfn_arr, rule, msr->msc_rule_mptmp);
if (vx == NULL) {
lua_pushnil(L);
return 0;
}
/* Return variable value. */
lua_pushlstring(L, vx->value, vx->value_len);
return 1;
}
/**
*
*/
static int l_getvars(lua_State *L) {
const apr_array_header_t *tarr;
const apr_table_entry_t *telts;
apr_table_t *vartable = NULL;
apr_array_header_t *tfn_arr = NULL;
char *varname = NULL, *param = NULL;
modsec_rec *msr = NULL;
msre_rule *rule = NULL;
msre_var *vartemplate = NULL;
char *my_error_msg = NULL;
char *p1 = NULL;
int i;
/* Retrieve parameters. */
p1 = (char *)luaL_checkstring(L, 1);
/* Retrieve msr. */
lua_getglobal(L, "__msr");
msr = (modsec_rec *)lua_topointer(L, -1);
/* Retrieve rule. */
lua_getglobal(L, "__rule");
rule = (msre_rule *)lua_topointer(L, -1);
/* Extract the variable name and its parameter from the script. */
varname = apr_pstrdup(msr->msc_rule_mptmp, p1);
param = strchr(varname, '.');
if (param != NULL) {
*param = '\0';
param++;
}
/* Resolve transformation functions. */
tfn_arr = resolve_tfns(L, 2, msr, msr->msc_rule_mptmp);
lua_newtable(L);
/* Resolve variable. */
vartemplate = msre_create_var_ex(msr->msc_rule_mptmp, msr->modsecurity->msre,
varname, param, msr, &my_error_msg);
if (vartemplate == NULL) {
msr_log(msr, 1, "%s", my_error_msg);
/* Returning empty table. */
return 1;
}
vartable = generate_multi_var(msr, vartemplate, tfn_arr, rule, msr->msc_rule_mptmp);
tarr = apr_table_elts(vartable);
telts = (const apr_table_entry_t*)tarr->elts;
for (i = 0; i < tarr->nelts; i++) {
msre_var *var = (msre_var *)telts[i].val;
lua_pushnumber(L, i + 1); /* Index is not zero-based. */
lua_newtable(L); /* Per-parameter table. */
lua_pushstring(L, "name");
lua_pushlstring(L, var->name, strlen(var->name));
lua_settable(L, -3);
lua_pushstring(L, "value");
lua_pushlstring(L, var->value, var->value_len);
lua_settable(L, -3);
lua_settable(L, -3); /* Push one parameter into the results table. */
}
return 1;
} }
static const struct luaL_Reg mylib[] = { static const struct luaL_Reg mylib[] = {
{ "log", l_log }, { "log", l_log },
{ "getvar", l_getvar }, { "getvar", l_getvar },
{ "getvars", l_getvars },
{ NULL, NULL } { NULL, NULL }
}; };
@ -317,4 +379,3 @@ int lua_execute(msc_script *script, char *param, modsec_rec *msr, msre_rule *rul
return ((*error_msg != NULL) ? RULE_MATCH : RULE_NO_MATCH); return ((*error_msg != NULL) ? RULE_MATCH : RULE_NO_MATCH);
} }
#endif

View File

@ -11,8 +11,6 @@
#ifndef _MSC_LUA_H_ #ifndef _MSC_LUA_H_
#define _MSC_LUA_H_ #define _MSC_LUA_H_
#if defined(WITH_LUA)
typedef struct msc_script msc_script; typedef struct msc_script msc_script;
typedef struct msc_script_part msc_script_part; typedef struct msc_script_part msc_script_part;
@ -39,4 +37,3 @@ char DSOLOCAL *lua_compile(msc_script **script, const char *filename, apr_pool_t
int DSOLOCAL lua_execute(msc_script *script, char *param, modsec_rec *msr, msre_rule *rule, char **error_msg); int DSOLOCAL lua_execute(msc_script *script, char *param, modsec_rec *msr, msre_rule *rule, char **error_msg);
#endif #endif
#endif

View File

@ -1314,7 +1314,6 @@ msre_rule *msre_rule_create(msre_ruleset *ruleset,
return rule; return rule;
} }
#ifdef WITH_LUA
/** /**
* *
*/ */
@ -1362,7 +1361,6 @@ msre_rule *msre_rule_lua_create(msre_ruleset *ruleset,
return rule; return rule;
} }
#endif
/** /**
* Perform non-disruptive actions associated with the provided actionset. * Perform non-disruptive actions associated with the provided actionset.
@ -2001,11 +1999,9 @@ apr_status_t msre_rule_process(msre_rule *rule, modsec_rec *msr) {
apr_pool_clear(msr->msc_rule_mptmp); apr_pool_clear(msr->msc_rule_mptmp);
} }
#if defined(WITH_LUA)
if (rule->type == RULE_TYPE_LUA) { if (rule->type == RULE_TYPE_LUA) {
return msre_rule_process_lua(rule, msr); return msre_rule_process_lua(rule, msr);
} }
#endif
return msre_rule_process_normal(rule, msr); return msre_rule_process_normal(rule, msr);
} }

View File

@ -65,9 +65,11 @@ int DSOLOCAL msre_parse_generic(apr_pool_t *pool, const char *text, apr_table_t
int DSOLOCAL rule_id_in_range(int ruleid, const char *range); int DSOLOCAL rule_id_in_range(int ruleid, const char *range);
msre_var DSOLOCAL *generate_single_var(modsec_rec *msr, msre_var *var, msre_rule *rule, msre_var DSOLOCAL *generate_single_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr,
apr_pool_t *mptmp); msre_rule *rule, apr_pool_t *mptmp);
apr_table_t DSOLOCAL *generate_multi_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr,
msre_rule *rule, apr_pool_t *mptmp);
/* Structures with the corresponding functions */ /* Structures with the corresponding functions */
@ -143,9 +145,8 @@ struct msre_rule {
unsigned int execution_time; unsigned int execution_time;
#endif #endif
#if defined(WITH_LUA) /* Compiled Lua script. */
msc_script *script; msc_script *script;
#endif
}; };
msre_rule DSOLOCAL *msre_rule_create(msre_ruleset *ruleset, msre_rule DSOLOCAL *msre_rule_create(msre_ruleset *ruleset,

View File

@ -39,21 +39,118 @@ static void msre_engine_action_register(msre_engine *engine, const char *name, u
/** /**
* Generates a single variable (from the supplied metadata). * Generates a single variable (from the supplied metadata).
*/ */
msre_var *generate_single_var(modsec_rec *msr, msre_var *var, msre_rule *rule, msre_var *generate_single_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr,
apr_pool_t *mptmp) msre_rule *rule, apr_pool_t *mptmp)
{ {
apr_table_t *vartab = NULL; apr_table_t *vartab = NULL;
const apr_table_entry_t *te = NULL; const apr_table_entry_t *te = NULL;
const apr_array_header_t *arr = NULL; const apr_array_header_t *arr = NULL;
msre_var *rvar = NULL;
int i;
/* Sanity check. */
if ((var == NULL)||(var->metadata == NULL)||(var->metadata->generate == NULL)) return NULL;
if (var->metadata->generate == NULL) return NULL;
vartab = apr_table_make(mptmp, 16); vartab = apr_table_make(mptmp, 16);
var->metadata->generate(msr, var, rule, vartab, mptmp); var->metadata->generate(msr, var, rule, vartab, mptmp);
arr = apr_table_elts(vartab); arr = apr_table_elts(vartab);
if (arr->nelts == 0) return NULL; if (arr->nelts == 0) return NULL;
te = (apr_table_entry_t *)arr->elts; te = (apr_table_entry_t *)arr->elts;
return (msre_var *)te[0].val; rvar = (msre_var *)te[0].val;
/* Return straight away if there were no
* transformation functions supplied.
*/
if ((tfn_arr == NULL)||(tfn_arr->nelts == 0)) {
return rvar;
}
/* Copy the value so that we can transform it in piece. */
rvar->value = apr_pstrndup(mptmp, rvar->value, rvar->value_len);
/* Transform rvar in a loop. */
for (i = 0; i < tfn_arr->nelts; i++) {
msre_tfn_metadata *tfn = ((msre_tfn_metadata **)tfn_arr->elts)[i];
char *rval;
int rc;
long int rval_len;
rc = tfn->execute(mptmp, (unsigned char *)rvar->value,
rvar->value_len, &rval, &rval_len);
rvar->value = rval;
rvar->value_len = rval_len;
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "T (%d) %s: \"%s\"", rc, tfn->name,
log_escape_nq_ex(mptmp, rvar->value, rvar->value_len));
}
}
return rvar;
}
/**
*
*/
apr_table_t *generate_multi_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr,
msre_rule *rule, apr_pool_t *mptmp)
{
const apr_array_header_t *tarr;
const apr_table_entry_t *telts;
apr_table_t *vartab = NULL, *tvartab = NULL;
msre_var *rvar = NULL;
int i, j;
/* Sanity check. */
if ((var == NULL)||(var->metadata == NULL)||(var->metadata->generate == NULL)) return NULL;
/* Generate variables. */
vartab = apr_table_make(mptmp, 16);
var->metadata->generate(msr, var, rule, vartab, mptmp);
/* Return straight away if there were no
* transformation functions supplied.
*/
if ((tfn_arr == NULL)||(tfn_arr->nelts == 0)) {
return vartab;
}
tvartab = apr_table_make(mptmp, 16);
tarr = apr_table_elts(vartab);
telts = (const apr_table_entry_t*)tarr->elts;
for (j = 0; j < tarr->nelts; j++) {
rvar = (msre_var *)telts[j].val;
/* Copy the value so that we can transform it in piece. */
rvar->value = apr_pstrndup(mptmp, rvar->value, rvar->value_len);
/* Transform rvar in a loop. */
for (i = 0; i < tfn_arr->nelts; i++) {
msre_tfn_metadata *tfn = ((msre_tfn_metadata **)tfn_arr->elts)[i];
char *rval;
int rc;
long int rval_len;
rc = tfn->execute(mptmp, (unsigned char *)rvar->value,
rvar->value_len, &rval, &rval_len);
rvar->value = rval;
rvar->value_len = rval_len;
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "T (%d) %s: \"%s\"", rc, tfn->name,
log_escape_nq_ex(mptmp, rvar->value, rvar->value_len));
}
}
apr_table_addn(tvartab, rvar->name, (void *)rvar);
}
return tvartab;
} }
/** /**
@ -137,7 +234,7 @@ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t
var_resolved = msre_create_var_ex(mptmp, msr->modsecurity->msre, var_name, var_value, var_resolved = msre_create_var_ex(mptmp, msr->modsecurity->msre, var_name, var_value,
msr, &my_error_msg); msr, &my_error_msg);
if (var_resolved != NULL) { if (var_resolved != NULL) {
var_generated = generate_single_var(msr, var_resolved, rule, mptmp); var_generated = generate_single_var(msr, var_resolved, NULL, rule, mptmp);
if (var_generated != NULL) { if (var_generated != NULL) {
part = (msc_string *)apr_pcalloc(mptmp, sizeof(msc_string)); part = (msc_string *)apr_pcalloc(mptmp, sizeof(msc_string));
if (part == NULL) return -1; if (part == NULL) return -1;
@ -1457,7 +1554,6 @@ static char *msre_action_exec_validate(msre_engine *engine, msre_action *action)
/* TODO Support relative filenames. */ /* TODO Support relative filenames. */
#ifdef WITH_LUA
/* Process Lua scripts internally. */ /* Process Lua scripts internally. */
if (strlen(filename) > 4) { if (strlen(filename) > 4) {
char *p = filename + strlen(filename) - 4; char *p = filename + strlen(filename) - 4;
@ -1472,7 +1568,6 @@ static char *msre_action_exec_validate(msre_engine *engine, msre_action *action)
action->param_data = script; action->param_data = script;
} }
} }
#endif
return NULL; return NULL;
} }

View File

@ -3,7 +3,7 @@
<title>ModSecurity Reference Manual</title> <title>ModSecurity Reference Manual</title>
<articleinfo> <articleinfo>
<releaseinfo>Version 2.5.0-rc1/ (December 19, 2007)</releaseinfo> <releaseinfo>Version 2.5.0-rc1/ (December 21, 2007)</releaseinfo>
<copyright> <copyright>
<year>2004-2007</year> <year>2004-2007</year>
@ -300,6 +300,11 @@
installed on the server.</para> installed on the server.</para>
</listitem> </listitem>
<listitem>
<para>Install the latest version of Lua in the 5.1.x branch, if it
isn't already installed on the server.</para>
</listitem>
<listitem> <listitem>
<para>Unpack the ModSecurity archive</para> <para>Unpack the ModSecurity archive</para>
</listitem> </listitem>
@ -315,14 +320,13 @@
<listitem> <listitem>
<para>Edit Makefile to configure the correct include path for libxml <para>Edit Makefile to configure the correct include path for libxml
(for example: <filename (for example <filename moreinfo="none">-I
moreinfo="none">INCLUDES=-I/usr/include/libxml2</filename>)</para> /usr/include/libxml2</filename>)</para>
</listitem> </listitem>
<listitem> <listitem>
<para>(Optional) If you want to use Lua scripting add <para>Edit Makefile to configure the correct incpude path for Lua (for
<literal>-DWITH_LUA</literal> and configure the path to Lua include example <literal>-I /usr/include/lua5.1</literal>).</para>
files (for example <literal>-I /usr/include/lua5.1</literal>).</para>
</listitem> </listitem>
<listitem> <listitem>
@ -339,19 +343,18 @@
</listitem> </listitem>
<listitem> <listitem>
<para>Add one line to your configuration to load libxml2: <filename <para>Load libxml2 before ModSecurity: <filename
moreinfo="none">LoadFile /usr/lib/libxml2.so</filename></para> moreinfo="none">LoadFile /usr/lib/libxml2.so</filename></para>
</listitem> </listitem>
<listitem> <listitem>
<para>(Optional) Add one line to load Lua before ModSecurity: <para>Load Lua before ModSecurity: <literal>LoadFile
<literal>LoadFile /usr/lib/liblua5.1.so</literal>.</para> /usr/lib/liblua5.1.so</literal>.</para>
</listitem> </listitem>
<listitem> <listitem>
<para>Add one line to your configuration to load ModSecurity: <literal <para>Load ModSecurity itself: <literal moreinfo="none">LoadModule
moreinfo="none">LoadModule security2_module security2_module modules/mod_security2.so</literal></para>
modules/mod_security2.so</literal></para>
</listitem> </listitem>
<listitem> <listitem>
@ -1805,6 +1808,12 @@ ServerAlias www.app2.com
<literal>SecRuleScript</literal> resides. This allows you to place your <literal>SecRuleScript</literal> resides. This allows you to place your
script in the same folder as the configuration files using them.</para> script in the same folder as the configuration files using them.</para>
<note>
<para>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.</para>
</note>
<para>Example script:</para> <para>Example script:</para>
<programlisting>-- Your script must define the <emphasis>main</emphasis> entry <programlisting>-- Your script must define the <emphasis>main</emphasis> entry
@ -1816,33 +1825,65 @@ function main()
m.log(1, "Hello world!"); m.log(1, "Hello world!");
-- Retrieve one variable. -- Retrieve one variable.
var1 = m.getvar("REMOTE_ADDR"); local var1 = m.getvar("REMOTE_ADDR");
-- Retrieve one variable, applying one transformation function. -- Retrieve one variable, applying one transformation function.
-- The second parameter is a string. -- The second parameter is a string.
var2 = m.getvar("REQUEST_URI", "normalisePath"); local var2 = m.getvar("REQUEST_URI", "normalisePath");
-- Retrieve one variable, applying several transformation functions. -- Retrieve one variable, applying several transformation functions.
-- The second parameter is now a list. You should note that m.getvar() -- The second parameter is now a list. You should note that m.getvar()
-- requires the use of comma to separate collection names from -- requires the use of comma to separate collection names from
-- variable names. This is because only one variable is returned. -- variable names. This is because only one variable is returned.
var3 = m.getvar("ARGS.p", { "lowercase", "compressWhitespace" } ); local var3 = m.getvar("ARGS.p", { "lowercase", "compressWhitespace" } );
-- If you want this rule to match return a string -- If you want this rule to match return a string
-- containing the error message. It is a good idea to mention -- containing the error message. The message <emphasis>must</emphasis> contain the name
-- where the problem is located. -- of the variable where the problem is located.
-- return "Variable ARGS:p looks suspicious!" -- return "Variable ARGS:p looks suspicious!"
-- Otherwise, simply return null. -- Otherwise, simply return null.
return null; return null;
end</programlisting> end</programlisting>
<para>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.</para>
<para>Example showing use of <literal>m.getvars()</literal> to retrieve
many variables at once:</para>
<programlisting>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, "&lt;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 null;
end</programlisting>
<note> <note>
<para>Go to <ulink url="http://www.lua.org">http://www.lua.org</ulink> <para>Go to <ulink url="http://www.lua.org">http://www.lua.org</ulink>
to find more about the Lua programming language. The reference manual to find more about the Lua programming language. The reference manual
too is available online, at <ulink too is available online, at <ulink
url="http://www.lua.org/manual/5.1/">http://www.lua.org/manual/5.1/</ulink>.</para> url="http://www.lua.org/manual/5.1/">http://www.lua.org/manual/5.1/</ulink>.</para>
</note> </note>
<note>
<para>Lua support is marked as <emphasis>experimental</emphasis>
because the way the scripts are written and function names may still
change while we are working for the best implementation style.</para>
</note>
</section> </section>
<section> <section>
@ -3926,9 +3967,8 @@ SecRule IP:AUTH_ATTEMPT "@gt 25" \
<title><literal>exec</literal></title> <title><literal>exec</literal></title>
<para><emphasis>Description:</emphasis> Executes an external <para><emphasis>Description:</emphasis> Executes an external
script/binary supplied as parameter. As of v2.5, when the support for script/binary supplied as parameter. As of v2.5, if tge parameter
Lua scripting is enabled, and the parameter supplied to supplied to <literal>exec</literal> is a Lua script (detected by the
<literal>exec</literal> is a Lua script (detected by the
<filename>.lua</filename> extension) the script will be processed <filename>.lua</filename> extension) the script will be processed
<emphasis>internally</emphasis>. This means you will get direct access <emphasis>internally</emphasis>. This means you will get direct access
to the internal request context from the script. Please read the to the internal request context from the script. Please read the
@ -3945,8 +3985,7 @@ SecRule REQUEST_URI "^/cgi-bin/script\.pl" \
"log,<emphasis>exec:/usr/local/apache/bin/test.sh</emphasis>" "log,<emphasis>exec:/usr/local/apache/bin/test.sh</emphasis>"
# The following is going to process /usr/local/apache/conf/exec.lua # The following is going to process /usr/local/apache/conf/exec.lua
# internally as a Lua script on rule match, provided ModSecurity was # internally as a Lua script on rule match.
# compiled with Lua support enabled.
SecRule ARGS:p attack log,<emphasis>exec:/usr/local/apache/conf/exec.lua</emphasis></programlisting> SecRule ARGS:p attack log,<emphasis>exec:/usr/local/apache/conf/exec.lua</emphasis></programlisting>
<note> <note>
@ -4878,10 +4917,9 @@ SecRule ARGS:route "!<emphasis>@endsWith %{REQUEST_ADDR}</emphasis>" t:none,deny
extracted from the request. As of v2.5, if the supplied filename is not extracted from the request. As of v2.5, if the supplied filename is not
absolute it is treated as relative to the directory in which the absolute it is treated as relative to the directory in which the
configuration file resides. Also as of v2.5 if the filename is configuration file resides. Also as of v2.5 if the filename is
determined to be a Lua script (based on its extension) and the Lua determined to be a Lua script (based on its extension) the script will
support is compiled in, the script will be processed by the internal be processed by the internal engine. As such it will have full access to
engine. As such it will have full access to the ModSecurity the ModSecurity context.</para>
context.</para>
<para>Example of using an external binary/script:</para> <para>Example of using an external binary/script:</para>