mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-09-29 19:24:29 +03:00
Adds support to SecDefaultAction configuration directive
This commit is contained in:
@@ -88,6 +88,7 @@ class Action {
|
||||
Assay *assay);
|
||||
virtual bool evaluate(Rule *rule, Assay *assay);
|
||||
virtual bool init(std::string *error) { return true; }
|
||||
virtual bool isDisruptive() { return false; }
|
||||
|
||||
static Action *instantiate(const std::string& name);
|
||||
|
||||
|
@@ -27,7 +27,9 @@ namespace ModSecurity {
|
||||
namespace actions {
|
||||
|
||||
Phase::Phase(std::string action)
|
||||
: Action(action) {
|
||||
: Action(action),
|
||||
m_secRulesPhase(0),
|
||||
phase(0) {
|
||||
this->action_kind = ConfigurationKind;
|
||||
std::string a = action;
|
||||
a.erase(0, 6);
|
||||
@@ -42,20 +44,25 @@ Phase::Phase(std::string action)
|
||||
this->phase = 0;
|
||||
if (tolower(a) == "request") {
|
||||
this->phase = this->phase + ModSecurity::Phases::RequestHeadersPhase;
|
||||
m_secRulesPhase = 2;
|
||||
}
|
||||
if (tolower(a) == "response") {
|
||||
this->phase = this->phase + ModSecurity::Phases::ResponseBodyPhase;
|
||||
m_secRulesPhase = 4;
|
||||
}
|
||||
if (tolower(a) == "logging") {
|
||||
this->phase = this->phase + ModSecurity::Phases::LoggingPhase;
|
||||
m_secRulesPhase = 5;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->phase == 0) {
|
||||
/* Phase 0 is something new, we want to use as ConnectionPhase */
|
||||
this->phase = ModSecurity::Phases::ConnectionPhase;
|
||||
m_secRulesPhase = 2;
|
||||
} else {
|
||||
/* Otherwise we want to shift the rule to the correct phase */
|
||||
m_secRulesPhase = phase;
|
||||
this->phase = phase + ModSecurity::Phases::RequestHeadersPhase - 1;
|
||||
}
|
||||
}
|
||||
|
@@ -36,6 +36,7 @@ class Phase : public Action {
|
||||
|
||||
bool evaluate(Rule *rule, Assay *assay) override;
|
||||
int phase;
|
||||
int m_secRulesPhase;
|
||||
};
|
||||
|
||||
} // namespace actions
|
||||
|
@@ -16,20 +16,25 @@ class Driver;
|
||||
}
|
||||
}
|
||||
|
||||
#include "modsecurity/modsecurity.h"
|
||||
|
||||
#include "actions/action.h"
|
||||
#include "actions/audit_log.h"
|
||||
#include "actions/ctl_audit_log_parts.h"
|
||||
#include "actions/set_var.h"
|
||||
#include "actions/severity.h"
|
||||
#include "actions/msg.h"
|
||||
#include "actions/phase.h"
|
||||
#include "actions/log_data.h"
|
||||
#include "actions/rev.h"
|
||||
#include "actions/tag.h"
|
||||
#include "actions/transformations/transformation.h"
|
||||
#include "actions/transformations/none.h"
|
||||
#include "operators/operator.h"
|
||||
#include "rule.h"
|
||||
#include "utils/geo_lookup.h"
|
||||
#include "audit_log.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "variables/variations/count.h"
|
||||
#include "variables/variations/exclusion.h"
|
||||
@@ -47,6 +52,8 @@ class Driver;
|
||||
#include "variables/time_wday.h"
|
||||
#include "variables/time_year.h"
|
||||
|
||||
using ModSecurity::ModSecurity;
|
||||
|
||||
using ModSecurity::actions::Action;
|
||||
using ModSecurity::actions::CtlAuditLogParts;
|
||||
using ModSecurity::actions::SetVar;
|
||||
@@ -54,6 +61,8 @@ using ModSecurity::actions::Severity;
|
||||
using ModSecurity::actions::Tag;
|
||||
using ModSecurity::actions::Rev;
|
||||
using ModSecurity::actions::Msg;
|
||||
using ModSecurity::actions::Phase;
|
||||
using ModSecurity::actions::transformations::None;
|
||||
using ModSecurity::actions::LogData;
|
||||
using ModSecurity::actions::transformations::Transformation;
|
||||
using ModSecurity::operators::Operator;
|
||||
@@ -181,6 +190,8 @@ using ModSecurity::Variables::Variable;
|
||||
%token <std::string> CONFIG_DIR_DEBUG_LOG
|
||||
%token <std::string> CONFIG_DIR_DEBUG_LVL
|
||||
|
||||
%token <std::string> CONFIG_DIR_SEC_DEFAULT_ACTION
|
||||
|
||||
%token <std::string> VARIABLE
|
||||
%token <std::string> RUN_TIME_VAR_DUR
|
||||
%token <std::string> RUN_TIME_VAR_ENV
|
||||
@@ -345,6 +356,43 @@ expression:
|
||||
);
|
||||
driver.addSecRule(rule);
|
||||
}
|
||||
| CONFIG_DIR_SEC_DEFAULT_ACTION SPACE QUOTATION_MARK actions QUOTATION_MARK
|
||||
{
|
||||
std::vector<Action *> *actions = $4;
|
||||
std::vector<Action *> checkedActions;
|
||||
int definedPhase = -1;
|
||||
int secRuleDefinedPhase = -1;
|
||||
for (Action *a : *actions) {
|
||||
Phase *phase = dynamic_cast<Phase *>(a);
|
||||
if (phase != NULL) {
|
||||
definedPhase = phase->phase;
|
||||
secRuleDefinedPhase = phase->m_secRulesPhase;
|
||||
} else if (a->action_kind == Action::RunTimeOnlyIfMatchKind ||
|
||||
a->action_kind == Action::RunTimeBeforeMatchAttemptKind) {
|
||||
None *none = dynamic_cast<None *>(a);
|
||||
if (none != NULL) {
|
||||
driver.parserError << "The transformation none is not suitable to be part of the SecDefaultActions";
|
||||
YYERROR;
|
||||
}
|
||||
checkedActions.push_back(a);
|
||||
} else {
|
||||
driver.parserError << "The action '" << a->action << "' is not suitable to be part of the SecDefaultActions";
|
||||
YYERROR;
|
||||
}
|
||||
}
|
||||
if (definedPhase == -1) {
|
||||
definedPhase = ModSecurity::ModSecurity::Phases::RequestHeadersPhase;
|
||||
}
|
||||
|
||||
if (!driver.defaultActions[definedPhase].empty()) {
|
||||
driver.parserError << "SecDefaultActions can only be placed once per phase and configuration context. Phase " << secRuleDefinedPhase << " was informed already.";
|
||||
YYERROR;
|
||||
}
|
||||
|
||||
for (Action *a : checkedActions) {
|
||||
driver.defaultActions[definedPhase].push_back(a);
|
||||
}
|
||||
}
|
||||
| CONFIG_DIR_RULE_ENG SPACE CONFIG_VALUE_OFF
|
||||
{
|
||||
driver.secRuleEngine = ModSecurity::Rules::DisabledRuleEngine;
|
||||
|
@@ -38,6 +38,8 @@ ACTION_CTL_AUDIT_LOG_PARTS (?i:ctl:auditLogParts)
|
||||
DIRECTIVE (?i:SecRule)
|
||||
LOG_DATA (?i:logdata)
|
||||
|
||||
CONFIG_DIR_SEC_DEFAULT_ACTION (?i:SecDefaultAction)
|
||||
|
||||
CONFIG_DIR_PCRE_MATCH_LIMIT_RECURSION (?i:SecPcreMatchLimitRecursion)
|
||||
CONFIG_DIR_PCRE_MATCH_LIMIT (?i:SecPcreMatchLimit)
|
||||
CONGIG_DIR_RESPONSE_BODY_MP (?i:SecResponseBodyMimeType)
|
||||
@@ -241,6 +243,7 @@ CONFIG_DIR_UNICODE_MAP_FILE (?i:SecUnicodeMapFile)
|
||||
{CONFIG_VALUE_PROCESS_PARTIAL} { return yy::seclang_parser::make_CONFIG_VALUE_PROCESS_PARTIAL(yytext, *driver.loc.back()); }
|
||||
{CONFIG_VALUE_REJECT} { return yy::seclang_parser::make_CONFIG_VALUE_REJECT(yytext, *driver.loc.back()); }
|
||||
|
||||
{CONFIG_DIR_SEC_DEFAULT_ACTION} { return yy::seclang_parser::make_CONFIG_DIR_SEC_DEFAULT_ACTION(yytext, *driver.loc.back()); }
|
||||
|
||||
<EXPECTING_OPERATOR>{
|
||||
["][^@]{FREE_TEXT}["] { BEGIN(INITIAL); return yy::seclang_parser::make_FREE_TEXT(yytext, *driver.loc.back()); }
|
||||
|
22
src/rule.cc
22
src/rule.cc
@@ -152,6 +152,22 @@ bool Rule::evaluate(Assay *assay) {
|
||||
none++;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for transformations on the SecDefaultAction
|
||||
// Notice that first we make sure that won't be a t:none
|
||||
// on the target rule.
|
||||
if (none == 0) {
|
||||
for (Action *a : assay->m_rules->defaultActions[this->phase]) {
|
||||
if (a->action_kind == actions::Action::RunTimeBeforeMatchAttemptKind) {
|
||||
value = a->evaluate(value, assay);
|
||||
assay->debug(9, "(SecDefaultAction) T (" + \
|
||||
std::to_string(transformations) + ") " + \
|
||||
a->name + ": \"" + value +"\"");
|
||||
transformations++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Action *a : this->actions_runtime_pre) {
|
||||
None *z = dynamic_cast<None *>(a);
|
||||
if (none == 0) {
|
||||
@@ -206,6 +222,12 @@ bool Rule::evaluate(Assay *assay) {
|
||||
assay->delete_variable("MATCHED_VARS_NAMES:" + v.first);
|
||||
}
|
||||
if (this->chained && chainResult == true || !this->chained) {
|
||||
for (Action *a : assay->m_rules->defaultActions[this->phase]) {
|
||||
if (a->action_kind == actions::Action::RunTimeOnlyIfMatchKind) {
|
||||
assay->debug(4, "(SecDefaultAction) Running action: " + a->action);
|
||||
a->evaluate(this, assay);
|
||||
}
|
||||
}
|
||||
for (Action *a :
|
||||
this->actions_runtime_pos) {
|
||||
assay->debug(4, "Running action: " + a->action);
|
||||
|
14
src/rules.cc
14
src/rules.cc
@@ -208,6 +208,20 @@ int Rules::merge(Driver *from) {
|
||||
this->requestBodyLimitAction = from->requestBodyLimitAction;
|
||||
this->responseBodyLimitAction = from->responseBodyLimitAction;
|
||||
|
||||
/*
|
||||
*
|
||||
* default Actions is something per configuration context, there is
|
||||
* need to merge anything.
|
||||
*
|
||||
*/
|
||||
for (int i = 0; i < ModSecurity::Phases::NUMBER_OF_PHASES; i++) {
|
||||
std::vector<Action *> actions = from->defaultActions[i];
|
||||
this->defaultActions[i].clear();
|
||||
for (int j = 0; j < actions.size(); j++) {
|
||||
Action *action = actions[j];
|
||||
this->defaultActions[i].push_back(action);
|
||||
}
|
||||
}
|
||||
|
||||
if (from->audit_log != NULL && this->audit_log != NULL) {
|
||||
this->audit_log->refCountDecreaseAndCheck();
|
||||
|
27
src/utils.cc
27
src/utils.cc
@@ -49,6 +49,33 @@
|
||||
|
||||
namespace ModSecurity {
|
||||
|
||||
std::string phase_name(int x) {
|
||||
switch(x) {
|
||||
case ModSecurity::Phases::ConnectionPhase:
|
||||
return "Connection Phase";
|
||||
break;
|
||||
case ModSecurity::Phases::UriPhase:
|
||||
return "URI Phase";
|
||||
break;
|
||||
case ModSecurity::Phases::RequestHeadersPhase:
|
||||
return "Request Headers";
|
||||
break;
|
||||
case ModSecurity::Phases::RequestBodyPhase:
|
||||
return "Request Headers";
|
||||
break;
|
||||
case ModSecurity::Phases::ResponseHeadersPhase:
|
||||
return "Response Headers";
|
||||
break;
|
||||
case ModSecurity::Phases::ResponseBodyPhase:
|
||||
return "Reponse Body";
|
||||
break;
|
||||
case ModSecurity::Phases::LoggingPhase:
|
||||
return "Logging";
|
||||
break;
|
||||
}
|
||||
return "Phase '" + std::to_string(x) + "' is not known.";
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> split(std::string str, char delimiter) {
|
||||
std::vector<std::string> internal;
|
||||
|
@@ -44,6 +44,7 @@ namespace ModSecurity {
|
||||
std::string string_to_hex(const std::string& input);
|
||||
int urldecode_uni_nonstrict_inplace_ex(Assay *assay, unsigned char *input,
|
||||
int64_t input_len, int *changed);
|
||||
std::string phase_name(int x);
|
||||
} // namespace ModSecurity
|
||||
|
||||
#define SRC_UTILS_H_
|
||||
|
Reference in New Issue
Block a user