Adds support to the allow action

This commit is contained in:
Felipe Zimmerle 2016-06-30 20:42:30 -03:00
parent e77e4c4c14
commit f72bd587ec
No known key found for this signature in database
GPG Key ID: E6DFB08CE8B11277
11 changed files with 287 additions and 25 deletions

View File

@ -224,4 +224,5 @@ TESTS+=test/test-cases/regression/variable-SERVER_NAME.json
TESTS+=test/test-cases/regression/operator-UnconditionalMatch.json
TESTS+=test/test-cases/regression/request-body-parser-json.json
TESTS+=test/test-cases/regression/action-skip.json
TESTS+=test/test-cases/regression/action-allow.json

View File

@ -73,6 +73,7 @@ class Rules;
class RuleMessage;
namespace actions {
class Action;
enum AllowType : short;
}
namespace RequestBodyProcessor {
class XML;
@ -310,6 +311,11 @@ class Transaction {
*/
int m_skip_next;
/**
* If allow action was utilized, this variable holds the allow type.
*/
modsecurity::actions::AllowType m_allowType;
/**
* Holds the decode URI. Notice that m_uri holds the raw version
* of the URI.

View File

@ -78,6 +78,7 @@ VARIABLES = \
ACTIONS = \
actions/accuracy.cc \
actions/action.cc \
actions/allow.cc \
actions/audit_log.cc \
actions/block.cc \
actions/capture.cc \

58
src/actions/allow.cc Normal file
View File

@ -0,0 +1,58 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include "actions/allow.h"
#include <iostream>
#include <string>
#include "modsecurity/transaction.h"
#include "modsecurity/rule.h"
#include "src/utils.h"
#include "modsecurity/modsecurity.h"
namespace modsecurity {
namespace actions {
bool Allow::init(std::string *error) {
std::string a = tolower(m_parser_payload);
if (a == "phase") {
m_allowType = PhaseAllowType;
} else if (a == "request") {
m_allowType = RequestAllowType;
} else if (a == "") {
m_allowType = FromNowOneAllowType;
} else {
error->assign("Allow: if specified, the parameter most be: phase, request");
return false;
}
return true;
}
bool Allow::evaluate(Rule *rule, Transaction *transaction) {
transaction->debug(4, "Dropping the evaluation of upcoming rules " \
"in favor of an `allow' action of type: " \
+ allowTypeToName(m_allowType));
transaction->m_allowType = m_allowType;
return true;
}
} // namespace actions
} // namespace modsecurity

83
src/actions/allow.h Normal file
View File

@ -0,0 +1,83 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include <string>
#include "actions/action.h"
#ifndef SRC_ACTIONS_ALLOW_H_
#define SRC_ACTIONS_ALLOW_H_
#ifdef __cplusplus
class Transaction;
namespace modsecurity {
class Transaction;
class Rule;
namespace actions {
enum AllowType : short {
/**
*
*/
NoneAllowType,
/**
*
*/
RequestAllowType,
/**
*
*/
PhaseAllowType,
/**
*
*/
FromNowOneAllowType,
};
class Allow : public Action {
public:
explicit Allow(std::string action)
: Action(action, RunTimeOnlyIfMatchKind),
m_allowType(NoneAllowType) { }
bool init(std::string *error) override;
bool evaluate(Rule *rule, Transaction *transaction) override;
AllowType m_allowType;
static std::string allowTypeToName (AllowType a) {
if (a == NoneAllowType) {
return "None";
} else if (a = RequestAllowType) {
return "Request";
} else if (a = PhaseAllowType) {
return "Phase";
} else if (a = FromNowOneAllowType) {
return "FromNowOne";
} else {
return "Unknown";
}
}
};
} // namespace actions
} // namespace modsecurity
#endif
#endif // SRC_ACTIONS_ALLOW_H_

View File

@ -34,6 +34,7 @@ class Driver;
#include "actions/skip_after.h"
#include "actions/msg.h"
#include "actions/phase.h"
#include "actions/allow.h"
#include "actions/log_data.h"
#include "actions/maturity.h"
#include "actions/redirect.h"
@ -87,6 +88,7 @@ using modsecurity::actions::Rev;
using modsecurity::actions::Ver;
using modsecurity::actions::Msg;
using modsecurity::actions::Phase;
using modsecurity::actions::Allow;
using modsecurity::actions::transformations::None;
using modsecurity::actions::LogData;
using modsecurity::actions::Maturity;
@ -932,6 +934,15 @@ act:
YYERROR;
}
}
| ACTION_ALLOW
{
std::string error;
$$ = new Allow($1);
if ($$->init(&error) == false) {
driver.error(@0, error);
YYERROR;
}
}
| ACTION_PHASE
{
std::string error;
@ -986,24 +997,6 @@ act:
*/
$$ = Action::instantiate($1);
}
| ACTION_ALLOW
{
/*
TODO: allow is not implemented yet.
std::string error;
Allow *allow = new Allow($1);
if (allow->init(&error) == false) {
driver.parserError << error;
YYERROR;
}
$$ = allow;
*/
$$ = Action::instantiate($1);
}
| ACTION_REDIRECT
{
std::string error;

View File

@ -25,7 +25,7 @@ using modsecurity::split;
ACTION (?i:accuracy|append|block|capture|chain|deny|deprecatevar|drop|expirevar|id:[0-9]+|id:'[0-9]+'|log|multiMatch|noauditlog|nolog|pass|pause|prepend|proxy|sanitiseArg|sanitiseMatched|sanitiseMatchedBytes|sanitiseRequestHeader|sanitiseResponseHeader|setrsc|setenv|status:[0-9]+)
ACTION_XMLNS (?i:xmlns)
ACTION_ALLOW (?i:allow)
ACTION_ALLOW ((?i:allow:(?i:REQUEST|PHASE))|(?i:phase:'(?i:REQUEST|PHASE)')|(?i:allow))
ACTION_INITCOL (?i:initcol)
ACTION_ACCURACY (?i:accuracy)
@ -418,9 +418,7 @@ CONFIG_DIR_UNICODE_MAP_FILE (?i:SecUnicodeMapFile)
{LOG_DATA}:'{FREE_TEXT_QUOTE}' { return yy::seclang_parser::make_LOG_DATA(yytext, *driver.loc.back()); }
{ACTION_MSG}:'{FREE_TEXT_QUOTE}' { return yy::seclang_parser::make_ACTION_MSG(yytext, *driver.loc.back()); }
{ACTION_ALLOW}:'{FREE_TEXT_QUOTE}' { return yy::seclang_parser::make_ACTION_ALLOW(yytext, *driver.loc.back()); }
{ACTION_ALLOW}:{FREE_TEXT_QUOTE_COMMA} { return yy::seclang_parser::make_ACTION_ALLOW(yytext, *driver.loc.back()); }
{ACTION_ALLOW} { return yy::seclang_parser::make_ACTION_ALLOW("", *driver.loc.back()); }
{ACTION_ALLOW} { return yy::seclang_parser::make_ACTION_ALLOW(yytext, *driver.loc.back()); }
{ACTION_REDIRECT}:{FREE_TEXT} { return yy::seclang_parser::make_ACTION_REDIRECT(yytext, *driver.loc.back()); }
{ACTION_TAG}:'{FREE_TEXT_QUOTE}' { return yy::seclang_parser::make_ACTION_TAG(yytext, *driver.loc.back()); }
{ACTION_REV}:'{FREE_TEXT_QUOTE_COMMA}' { return yy::seclang_parser::make_ACTION_REV(yytext, *driver.loc.back()); }

View File

@ -183,6 +183,22 @@ int Rules::evaluate(int phase, Transaction *transaction) {
debug(9, "This phase consists of " + std::to_string(rules.size()) + \
" rule(s).");
if (transaction->m_allowType == actions::FromNowOneAllowType
&& phase != ModSecurity::Phases::LoggingPhase) {
debug(9, "Skipping all rules evaluation on this phase as request " \
"through the utilization of an `allow' action.");
return true;
}
if (transaction->m_allowType == actions::RequestAllowType
&& phase <= ModSecurity::Phases::RequestBodyPhase) {
debug(9, "Skipping all rules evaluation on this phase as request " \
"through the utilization of an `allow' action.");
return true;
}
if (transaction->m_allowType != actions::NoneAllowType) {
transaction->m_allowType = actions::NoneAllowType;
}
for (int i = 0; i < rules.size(); i++) {
Rule *rule = rules[i];
if (transaction->m_marker.empty() == false) {
@ -199,8 +215,11 @@ int Rules::evaluate(int phase, Transaction *transaction) {
} else if (transaction->m_skip_next > 0) {
transaction->m_skip_next--;
debug(9, "Skipped rule id '" + std::to_string(rule->rule_id) \
+ "' due to `skip' action. Still " + \
+ "' due to a `skip' action. Still " + \
std::to_string(transaction->m_skip_next) + " to be skipped.");
} else if (transaction->m_allowType != actions::NoneAllowType) {
debug(9, "Skipped rule id '" + std::to_string(rule->rule_id) \
+ "' as request trough the utilization of an `allow' action.");
} else {
rule->evaluate(transaction);
}

View File

@ -43,6 +43,7 @@
#include "src/unique_id.h"
#include "src/utils.h"
#include "modsecurity/rule.h"
#include "src/actions/allow.h"
using modsecurity::actions::Action;
using modsecurity::RequestBodyProcessor::Multipart;
@ -113,6 +114,7 @@ Transaction::Transaction(ModSecurity *ms, Rules *rules, void *logCbData)
m_responseHeadersNames(NULL),
m_responseContentType(NULL),
m_marker(""),
m_allowType(modsecurity::actions::NoneAllowType),
m_skip_next(0),
m_creationTimeStamp(cpu_seconds()),
m_logCbData(logCbData),

View File

@ -0,0 +1,101 @@
[
{
"enabled":1,
"version_min":300000,
"title":"Testing allow action 1/3",
"expected":{
"debug_log": "Skipped rule id '500066' as request trough the utilization of an `allow' action",
"http_code": 200
},
"client":{
"ip":"200.249.12.31",
"port":123
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*",
"User-Agent":"My sweet little browser",
"Cookie": "PHPSESSID=rAAAAAAA2t5uvjq435r4q7ib3vtdjq120"
},
"uri":"/?key=value&key=other_value",
"method":"GET"
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"rules":[
"SecRuleEngine On",
"SecAction \"phase:1,allow,msg:'ALLOWED',id:500065\"",
"SecAction \"phase:1,deny,msg:'DENIED',id:500066\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing allow action 1/3",
"expected":{
"debug_log": "",
"http_code": 500
},
"client":{
"ip":"200.249.12.31",
"port":123
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*",
"User-Agent":"My sweet little browser",
"Cookie": "PHPSESSID=rAAAAAAA2t5uvjq435r4q7ib3vtdjq120"
},
"uri":"/?key=value&key=other_value",
"method":"GET"
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"rules":[
"SecRuleEngine On",
"SecAction \"phase:1,allow:request,msg:'ALLOWED',id:500065\"",
"SecRule ARGS \"@contains value\" \"id:1,t:trim,status:500,deny,phase:3\""
]
},
{
"enabled":1,
"version_min":300000,
"title":"Testing allow action 1/3",
"expected":{
"debug_log": "",
"http_code": 500
},
"client":{
"ip":"200.249.12.31",
"port":123
},
"request":{
"headers":{
"Host":"localhost",
"User-Agent":"curl/7.38.0",
"Accept":"*/*",
"User-Agent":"My sweet little browser",
"Cookie": "PHPSESSID=rAAAAAAA2t5uvjq435r4q7ib3vtdjq120"
},
"uri":"/?key=value&key=other_value",
"method":"GET"
},
"server":{
"ip":"200.249.12.31",
"port":80
},
"rules":[
"SecRuleEngine On",
"SecAction \"phase:1,allow:phase,msg:'ALLOWED',id:500065\"",
"SecRule ARGS \"@contains value\" \"id:1,t:trim,status:500,deny,phase:3\""
]
}
]

View File

@ -4,7 +4,7 @@
"version_min":300000,
"title":"Testing skip action 1/3",
"expected":{
"debug_log": "\\[9\\] Skipped rule id \\'2\\' due to \\`skip\\' action."
"debug_log": "\\[9\\] Skipped rule id \\'2\\' due to a \\`skip\\' action."
},
"client":{
"ip":"200.249.12.31",
@ -74,7 +74,7 @@
"version_min":300000,
"title":"Testing skip action 3/3",
"expected":{
"debug_log": "\\[9\\] Skipped rule id \\'3\\' due to \\`skip\\' action."
"debug_log": "\\[9\\] Skipped rule id \\'3\\' due to a \\`skip\\' action."
},
"client":{
"ip":"200.249.12.31",