mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-16 07:56:12 +03:00
Adds support to SecResponseBodyLimit directive and OUTBOUND_DATA_ERROR var
This commit is contained in:
parent
8e59b1822c
commit
62fece7823
@ -48,6 +48,7 @@ class Rules {
|
|||||||
Rules()
|
Rules()
|
||||||
: m_referenceCount(0),
|
: m_referenceCount(0),
|
||||||
requestBodyLimit(0),
|
requestBodyLimit(0),
|
||||||
|
responseBodyLimit(0),
|
||||||
m_custom_debug_log(NULL) { }
|
m_custom_debug_log(NULL) { }
|
||||||
|
|
||||||
explicit Rules(DebugLog *custom_log)
|
explicit Rules(DebugLog *custom_log)
|
||||||
@ -126,6 +127,7 @@ class Rules {
|
|||||||
std::list<std::string> components;
|
std::list<std::string> components;
|
||||||
|
|
||||||
int requestBodyLimit;
|
int requestBodyLimit;
|
||||||
|
int responseBodyLimit;
|
||||||
AuditLog *audit_log;
|
AuditLog *audit_log;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
19
src/assay.cc
19
src/assay.cc
@ -718,6 +718,11 @@ int Assay::addResponseHeader(const unsigned char *key, size_t key_n,
|
|||||||
*/
|
*/
|
||||||
int Assay::processResponseBody() {
|
int Assay::processResponseBody() {
|
||||||
debug(4, "Starting phase RESPONSE_BODY. (SecRules 4)");
|
debug(4, "Starting phase RESPONSE_BODY. (SecRules 4)");
|
||||||
|
|
||||||
|
if (resolve_variable_first("OUTBOUND_DATA_ERROR") == NULL) {
|
||||||
|
store_variable("OUTBOUND_DATA_ERROR", "0");
|
||||||
|
}
|
||||||
|
|
||||||
this->m_rules->evaluate(ModSecurity::ResponseBodyPhase, this);
|
this->m_rules->evaluate(ModSecurity::ResponseBodyPhase, this);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -742,10 +747,16 @@ int Assay::processResponseBody() {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int Assay::appendResponseBody(const unsigned char *buf, size_t len) {
|
int Assay::appendResponseBody(const unsigned char *buf, size_t len) {
|
||||||
/**
|
int current_size = this->m_responseBody.tellp();
|
||||||
* as part of the confiurations or rules it is expected to
|
|
||||||
* set a higher value for this. Will not handle it for now.
|
debug(9, "Appending response body: " + std::to_string(len) + " bytes. " \
|
||||||
*/
|
"Limit set to: " + std::to_string(this->m_rules->responseBodyLimit));
|
||||||
|
|
||||||
|
if (this->m_rules->responseBodyLimit > 0
|
||||||
|
&& this->m_rules->responseBodyLimit < len + current_size) {
|
||||||
|
store_variable("OUTBOUND_DATA_ERROR", "1");
|
||||||
|
}
|
||||||
|
|
||||||
this->m_responseBody.write(reinterpret_cast<const char*>(buf), len);
|
this->m_responseBody.write(reinterpret_cast<const char*>(buf), len);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -21,6 +21,7 @@ Driver::Driver()
|
|||||||
: trace_scanning(false),
|
: trace_scanning(false),
|
||||||
trace_parsing(false),
|
trace_parsing(false),
|
||||||
requestBodyLimit(0),
|
requestBodyLimit(0),
|
||||||
|
responseBodyLimit(0),
|
||||||
audit_log(new ModSecurity::AuditLog()) {
|
audit_log(new ModSecurity::AuditLog()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,6 +88,7 @@ class Driver {
|
|||||||
bool sec_request_body_access;
|
bool sec_request_body_access;
|
||||||
bool sec_response_body_access;
|
bool sec_response_body_access;
|
||||||
int requestBodyLimit;
|
int requestBodyLimit;
|
||||||
|
int responseBodyLimit;
|
||||||
|
|
||||||
std::string debug_log_path;
|
std::string debug_log_path;
|
||||||
std::list<std::string> components;
|
std::list<std::string> components;
|
||||||
|
@ -64,6 +64,7 @@ using ModSecurity::Utils::GeoLookup;
|
|||||||
%token <std::string> DIRECTIVE
|
%token <std::string> DIRECTIVE
|
||||||
%token <std::string> CONFIG_DIRECTIVE
|
%token <std::string> CONFIG_DIRECTIVE
|
||||||
%token <std::string> CONFIG_DIR_REQ_BODY_LIMIT
|
%token <std::string> CONFIG_DIR_REQ_BODY_LIMIT
|
||||||
|
%token <std::string> CONFIG_DIR_RES_BODY_LIMIT
|
||||||
%token <std::string> CONFIG_DIR_RULE_ENG
|
%token <std::string> CONFIG_DIR_RULE_ENG
|
||||||
%token <std::string> CONFIG_DIR_REQ_BODY
|
%token <std::string> CONFIG_DIR_REQ_BODY
|
||||||
%token <std::string> CONFIG_DIR_RES_BODY
|
%token <std::string> CONFIG_DIR_RES_BODY
|
||||||
@ -255,6 +256,10 @@ expression:
|
|||||||
{
|
{
|
||||||
driver.requestBodyLimit = atoi($1.c_str());
|
driver.requestBodyLimit = atoi($1.c_str());
|
||||||
}
|
}
|
||||||
|
| CONFIG_DIR_RES_BODY_LIMIT
|
||||||
|
{
|
||||||
|
driver.responseBodyLimit = atoi($1.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
variables PIPE VARIABLE
|
variables PIPE VARIABLE
|
||||||
|
@ -21,8 +21,9 @@ ACTION (?i:accuracy|allow|append|auditlog|block|capture|chain|ctl|deny|
|
|||||||
ACTION_SEVERITY (?i:severity:[0-9]+|severity:'[0-9]+'|severity:(EMERGENCY|ALERT|CRITICAL|ERROR|WARNING|NOTICE|INFO|DEBUG)|severity:'(EMERGENCY|ALERT|CRITICAL|ERROR|WARNING|NOTICE|INFO|DEBUG)')
|
ACTION_SEVERITY (?i:severity:[0-9]+|severity:'[0-9]+'|severity:(EMERGENCY|ALERT|CRITICAL|ERROR|WARNING|NOTICE|INFO|DEBUG)|severity:'(EMERGENCY|ALERT|CRITICAL|ERROR|WARNING|NOTICE|INFO|DEBUG)')
|
||||||
DIRECTIVE SecRule
|
DIRECTIVE SecRule
|
||||||
|
|
||||||
CONFIG_DIRECTIVE SecRequestBodyLimitAction|SecRequestBodyNoFilesLimit|SecRequestBodyInMemoryLimit|SecPcreMatchLimitRecursion|SecPcreMatchLimit|SecResponseBodyMimeType|SecResponseBodyLimitAction|SecResponseBodyLimit|SecTmpDir|SecDataDir|SecArgumentSeparator|SecCookieFormat|SecStatusEngine
|
CONFIG_DIRECTIVE SecRequestBodyLimitAction|SecRequestBodyNoFilesLimit|SecRequestBodyInMemoryLimit|SecPcreMatchLimitRecursion|SecPcreMatchLimit|SecResponseBodyMimeType|SecResponseBodyLimitAction|SecTmpDir|SecDataDir|SecArgumentSeparator|SecCookieFormat|SecStatusEngine
|
||||||
CONFIG_DIR_REQ_BODY_LIMIT (?i:SecRequestBodyLimit)
|
CONFIG_DIR_REQ_BODY_LIMIT (?i:SecRequestBodyLimit)
|
||||||
|
CONFIG_DIR_RES_BODY_LIMIT (?i:SecResponseBodyLimit)
|
||||||
|
|
||||||
|
|
||||||
CONFIG_DIR_GEO_DB (?i:SecGeoLookupDb)
|
CONFIG_DIR_GEO_DB (?i:SecGeoLookupDb)
|
||||||
@ -59,7 +60,7 @@ OPERATORNOARG (?i:@detectSQLi|@detectXSS|@geoLookup|@validateUrlEncoding|@valida
|
|||||||
|
|
||||||
TRANSFORMATION t:(lowercase|urlDecodeUni|urlDecode|none|compressWhitespace|removeWhitespace|replaceNulls|removeNulls|htmlEntityDecode|jsDecode|cssDecode|trim)
|
TRANSFORMATION t:(lowercase|urlDecodeUni|urlDecode|none|compressWhitespace|removeWhitespace|replaceNulls|removeNulls|htmlEntityDecode|jsDecode|cssDecode|trim)
|
||||||
|
|
||||||
VARIABLE (?i:MULTIPART_STRICT_ERROR|MULTIPART_NAME|MULTIPART_FILENAME|MULTIPART_CRLF_LF_LINES|MATCHED_VAR_NAME|MATCHED_VARS_NAMES|MATCHED_VAR|MATCHED_VARS|INBOUND_DATA_ERROR|FULL_REQUEST|FILES|AUTH_TYPE|ARGS_NAMES|ARGS|QUERY_STRING|REMOTE_ADDR|REQUEST_BASENAME|REQUEST_BODY|REQUEST_COOKIES_NAMES|REQUEST_COOKIES|REQUEST_FILENAME|REQUEST_HEADERS_NAMES|REQUEST_HEADERS|REQUEST_METHOD|REQUEST_PROTOCOL|REQUEST_URI|RESPONSE_BODY|RESPONSE_CONTENT_LENGTH|RESPONSE_CONTENT_TYPE|RESPONSE_HEADERS_NAMES|RESPONSE_HEADERS|RESPONSE_PROTOCOL|RESPONSE_STATUS|TX|GEO)
|
VARIABLE (?i:MULTIPART_STRICT_ERROR|MULTIPART_NAME|MULTIPART_FILENAME|MULTIPART_CRLF_LF_LINES|MATCHED_VAR_NAME|MATCHED_VARS_NAMES|MATCHED_VAR|MATCHED_VARS|INBOUND_DATA_ERROR|OUTBOUND_DATA_ERROR|FULL_REQUEST|FILES|AUTH_TYPE|ARGS_NAMES|ARGS|QUERY_STRING|REMOTE_ADDR|REQUEST_BASENAME|REQUEST_BODY|REQUEST_COOKIES_NAMES|REQUEST_COOKIES|REQUEST_FILENAME|REQUEST_HEADERS_NAMES|REQUEST_HEADERS|REQUEST_METHOD|REQUEST_PROTOCOL|REQUEST_URI|RESPONSE_BODY|RESPONSE_CONTENT_LENGTH|RESPONSE_CONTENT_TYPE|RESPONSE_HEADERS_NAMES|RESPONSE_HEADERS|RESPONSE_PROTOCOL|RESPONSE_STATUS|TX|GEO)
|
||||||
RUN_TIME_VAR_DUR (?i:DURATION)
|
RUN_TIME_VAR_DUR (?i:DURATION)
|
||||||
RUN_TIME_VAR_ENV (?i:ENV)
|
RUN_TIME_VAR_ENV (?i:ENV)
|
||||||
RUN_TIME_VAR_BLD (?i:MODSEC_BUILD)
|
RUN_TIME_VAR_BLD (?i:MODSEC_BUILD)
|
||||||
@ -126,6 +127,8 @@ FREE_TEXT_NEW_LINE [^\"|\n]+
|
|||||||
|
|
||||||
%{ /* Request body limit */ %}
|
%{ /* Request body limit */ %}
|
||||||
{CONFIG_DIR_REQ_BODY_LIMIT}[ ]{CONFIG_VALUE_NUMBER} { return yy::seclang_parser::make_CONFIG_DIR_REQ_BODY_LIMIT(strchr(yytext, ' ') + 1, loc); }
|
{CONFIG_DIR_REQ_BODY_LIMIT}[ ]{CONFIG_VALUE_NUMBER} { return yy::seclang_parser::make_CONFIG_DIR_REQ_BODY_LIMIT(strchr(yytext, ' ') + 1, loc); }
|
||||||
|
%{ /* Reponse body limit */ %}
|
||||||
|
{CONFIG_DIR_RES_BODY_LIMIT}[ ]{CONFIG_VALUE_NUMBER} { return yy::seclang_parser::make_CONFIG_DIR_RES_BODY_LIMIT(strchr(yytext, ' ') + 1, loc); }
|
||||||
|
|
||||||
{CONFIG_COMPONENT_SIG}[ ]["]{FREE_TEXT}["] { return yy::seclang_parser::make_CONFIG_COMPONENT_SIG(strchr(yytext, ' ') + 2, loc); }
|
{CONFIG_COMPONENT_SIG}[ ]["]{FREE_TEXT}["] { return yy::seclang_parser::make_CONFIG_COMPONENT_SIG(strchr(yytext, ' ') + 2, loc); }
|
||||||
|
|
||||||
|
@ -168,6 +168,7 @@ int Rules::merge(Driver *from) {
|
|||||||
this->debug_level = from->debug_level;
|
this->debug_level = from->debug_level;
|
||||||
this->components = from->components;
|
this->components = from->components;
|
||||||
this->requestBodyLimit = from->requestBodyLimit;
|
this->requestBodyLimit = from->requestBodyLimit;
|
||||||
|
this->responseBodyLimit = from->responseBodyLimit;
|
||||||
|
|
||||||
if (m_custom_debug_log) {
|
if (m_custom_debug_log) {
|
||||||
this->debug_log = m_custom_debug_log->new_instance();
|
this->debug_log = m_custom_debug_log->new_instance();
|
||||||
@ -203,6 +204,7 @@ int Rules::merge(Rules *from) {
|
|||||||
this->sec_response_body_access = from->sec_response_body_access;
|
this->sec_response_body_access = from->sec_response_body_access;
|
||||||
this->components = from->components;
|
this->components = from->components;
|
||||||
this->requestBodyLimit = from->requestBodyLimit;
|
this->requestBodyLimit = from->requestBodyLimit;
|
||||||
|
this->responseBodyLimit = from->responseBodyLimit;
|
||||||
|
|
||||||
this->debug_log = from->debug_log;
|
this->debug_log = from->debug_log;
|
||||||
|
|
||||||
|
120
test/test-cases/regression/variable-OUTBOUND_DATA_ERROR.json
Normal file
120
test/test-cases/regression/variable-OUTBOUND_DATA_ERROR.json
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"enabled":1,
|
||||||
|
"version_min":300000,
|
||||||
|
"title":"Testing Variables :: OUTBOUND_DATA_ERROR (1/2)",
|
||||||
|
"client":{
|
||||||
|
"ip":"200.249.12.31",
|
||||||
|
"port":123
|
||||||
|
},
|
||||||
|
"server":{
|
||||||
|
"ip":"200.249.12.31",
|
||||||
|
"port":80
|
||||||
|
},
|
||||||
|
"request":{
|
||||||
|
"headers":{
|
||||||
|
"Host":"localhost",
|
||||||
|
"User-Agent":"curl/7.38.0",
|
||||||
|
"Accept":"*/*"
|
||||||
|
},
|
||||||
|
"uri":"/?key=value&key=other_value",
|
||||||
|
"protocol":"GET"
|
||||||
|
},
|
||||||
|
"response":{
|
||||||
|
"headers":{
|
||||||
|
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
|
||||||
|
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
|
||||||
|
"Content-Type":"text/html"
|
||||||
|
},
|
||||||
|
"body":[
|
||||||
|
"no need."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"expected":{
|
||||||
|
"debug_log":"Target value: \"0\" \\(Variable: OUTBOUND_DATA_ERROR\\)"
|
||||||
|
},
|
||||||
|
"rules":[
|
||||||
|
"SecRuleEngine On",
|
||||||
|
"SecDebugLog \/tmp\/modsec_debug.log",
|
||||||
|
"SecDebugLogLevel 9",
|
||||||
|
"SecRule OUTBOUND_DATA_ERROR \"@eq 1\" \"phase:4,pass,t:trim\""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"enabled":1,
|
||||||
|
"version_min":300000,
|
||||||
|
"title":"Testing Variables :: OUTBOUND_DATA_ERROR (2/2)",
|
||||||
|
"client":{
|
||||||
|
"ip":"200.249.12.31",
|
||||||
|
"port":123
|
||||||
|
},
|
||||||
|
"server":{
|
||||||
|
"ip":"200.249.12.31",
|
||||||
|
"port":80
|
||||||
|
},
|
||||||
|
"request":{
|
||||||
|
"headers":{
|
||||||
|
"Host":"localhost",
|
||||||
|
"User-Agent":"curl/7.38.0",
|
||||||
|
"Accept":"*/*",
|
||||||
|
"Content-Length":"330",
|
||||||
|
"Content-Type":"multipart/form-data; boundary=--------------------------756b6d74fa1a8ee2",
|
||||||
|
"Expect":"100-continue"
|
||||||
|
},
|
||||||
|
"uri":"/",
|
||||||
|
"protocol":"POST",
|
||||||
|
"body":[
|
||||||
|
"--------------------------756b6d74fa1a8ee2",
|
||||||
|
"Content-Disposition: form-data; name=\"name\"",
|
||||||
|
"",
|
||||||
|
"test",
|
||||||
|
"--------------------------756b6d74fa1a8ee2",
|
||||||
|
"Content-Disposition: form-data; name=\"filedata\"; filename=\"small_text_file.txt\"",
|
||||||
|
"Content-Type: text/plain",
|
||||||
|
"",
|
||||||
|
"This is a very small test file..",
|
||||||
|
"--------------------------756b6d74fa1a8ee2",
|
||||||
|
"Content-Disposition: form-data; name=\"filedata\"; filename=\"small_text_file.txt\"",
|
||||||
|
"Content-Type: text/plain",
|
||||||
|
"",
|
||||||
|
"This is another very small test file..",
|
||||||
|
"--------------------------756b6d74fa1a8ee2--"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"response":{
|
||||||
|
"headers":{
|
||||||
|
"Date":"Mon, 13 Jul 2015 20:02:41 GMT",
|
||||||
|
"Last-Modified":"Sun, 26 Oct 2014 22:33:37 GMT",
|
||||||
|
"Content-Type":"text/html"
|
||||||
|
},
|
||||||
|
"body":[
|
||||||
|
"--------------------------756b6d74fa1a8ee2",
|
||||||
|
"Content-Disposition: form-data; name=\"name\"",
|
||||||
|
"",
|
||||||
|
"test",
|
||||||
|
"--------------------------756b6d74fa1a8ee2",
|
||||||
|
"Content-Disposition: form-data; name=\"filedata\"; filename=\"small_text_file.txt\"",
|
||||||
|
"Content-Type: text/plain",
|
||||||
|
"",
|
||||||
|
"This is a very small test file..",
|
||||||
|
"--------------------------756b6d74fa1a8ee2",
|
||||||
|
"Content-Disposition: form-data; name=\"filedata\"; filename=\"small_text_file.txt\"",
|
||||||
|
"Content-Type: text/plain",
|
||||||
|
"",
|
||||||
|
"This is another very small test file..",
|
||||||
|
"--------------------------756b6d74fa1a8ee2--"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"expected":{
|
||||||
|
"debug_log":"Target value: \"1\" \\(Variable: OUTBOUND_DATA_ERROR\\)"
|
||||||
|
},
|
||||||
|
"rules":[
|
||||||
|
"SecRuleEngine On",
|
||||||
|
"SecDebugLog \/tmp\/modsec_debug.log",
|
||||||
|
"SecResponseBodyLimit 2",
|
||||||
|
"SecDebugLogLevel 9",
|
||||||
|
"SecRule OUTBOUND_DATA_ERROR \"@eq 1\" \"phase:4,pass,t:trim\""
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user