mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-15 23:55:03 +03:00
Adds support to SecResponseBodyMimeType
This commit is contained in:
parent
c2d9a153cb
commit
decf04d264
@ -194,6 +194,7 @@ class Assay {
|
|||||||
std::string *m_namesArgsGet;
|
std::string *m_namesArgsGet;
|
||||||
std::string *m_requestHeadersNames;
|
std::string *m_requestHeadersNames;
|
||||||
std::string *m_responseHeadersNames;
|
std::string *m_responseHeadersNames;
|
||||||
|
std::string *m_responseContentType;
|
||||||
double m_ARGScombinedSize;
|
double m_ARGScombinedSize;
|
||||||
/** TODO: Support to save double in the storage. */
|
/** TODO: Support to save double in the storage. */
|
||||||
std::string *m_ARGScombinedSizeStr;
|
std::string *m_ARGScombinedSizeStr;
|
||||||
|
@ -201,6 +201,7 @@ class RulesProperties {
|
|||||||
std::string audit_log_path;
|
std::string audit_log_path;
|
||||||
std::string audit_log_parts;
|
std::string audit_log_parts;
|
||||||
std::list<std::string> components;
|
std::list<std::string> components;
|
||||||
|
std::set<std::string> m_responseBodyTypeToBeInspected;
|
||||||
|
|
||||||
DebugLog *m_debugLog;
|
DebugLog *m_debugLog;
|
||||||
|
|
||||||
|
33
src/assay.cc
33
src/assay.cc
@ -105,6 +105,7 @@ Assay::Assay(ModSecurity *ms, Rules *rules, void *logCbData)
|
|||||||
m_requestBodyType(UnknownFormat),
|
m_requestBodyType(UnknownFormat),
|
||||||
m_requestHeadersNames(NULL),
|
m_requestHeadersNames(NULL),
|
||||||
m_responseHeadersNames(NULL),
|
m_responseHeadersNames(NULL),
|
||||||
|
m_responseContentType(NULL),
|
||||||
m_marker(""),
|
m_marker(""),
|
||||||
start(cpu_seconds()),
|
start(cpu_seconds()),
|
||||||
m_logCbData(logCbData),
|
m_logCbData(logCbData),
|
||||||
@ -127,6 +128,10 @@ Assay::Assay(ModSecurity *ms, Rules *rules, void *logCbData)
|
|||||||
m_collections.store("RESPONSE_HEADERS_NAMES", std::string(""));
|
m_collections.store("RESPONSE_HEADERS_NAMES", std::string(""));
|
||||||
this->m_responseHeadersNames = m_collections.resolveFirst(
|
this->m_responseHeadersNames = m_collections.resolveFirst(
|
||||||
"RESPONSE_HEADERS_NAMES");
|
"RESPONSE_HEADERS_NAMES");
|
||||||
|
m_collections.store("RESPONSE_CONTENT_TYPE", std::string(""));
|
||||||
|
this->m_responseContentType = m_collections.resolveFirst(
|
||||||
|
"RESPONSE_CONTENT_TYPE");
|
||||||
|
|
||||||
|
|
||||||
#ifndef NO_LOGS
|
#ifndef NO_LOGS
|
||||||
this->debug(4, "Initialising transaction");
|
this->debug(4, "Initialising transaction");
|
||||||
@ -860,7 +865,7 @@ int Assay::addResponseHeader(const std::string& key,
|
|||||||
this->m_collections.store("RESPONSE_HEADERS:" + key, value);
|
this->m_collections.store("RESPONSE_HEADERS:" + key, value);
|
||||||
|
|
||||||
if (tolower(key) == "content-type") {
|
if (tolower(key) == "content-type") {
|
||||||
this->m_collections.store("RESPONSE_CONTENT_TYPE", value);
|
this->m_responseContentType->assign(value);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -951,6 +956,21 @@ int Assay::processResponseBody() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::set<std::string> &bi = this->m_rules->m_responseBodyTypeToBeInspected;
|
||||||
|
auto t = bi.find(*m_responseContentType);
|
||||||
|
if (t == bi.end() && bi.empty() == false) {
|
||||||
|
#ifndef NO_LOGS
|
||||||
|
debug(5, "Response Content-Type is " + *m_responseContentType + \
|
||||||
|
". It is not marked to be inspected.");
|
||||||
|
std::string validContetTypes("");
|
||||||
|
for (std::set<std::string>::iterator i = bi.begin();
|
||||||
|
i != bi.end(); i++) {
|
||||||
|
validContetTypes.append(*i + " ");
|
||||||
|
}
|
||||||
|
debug(8, "Content-Type(s) marked to be inspected: " + validContetTypes);
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (m_collections.resolveFirst("OUTBOUND_DATA_ERROR") == NULL) {
|
if (m_collections.resolveFirst("OUTBOUND_DATA_ERROR") == NULL) {
|
||||||
m_collections.store("OUTBOUND_DATA_ERROR", "0");
|
m_collections.store("OUTBOUND_DATA_ERROR", "0");
|
||||||
}
|
}
|
||||||
@ -985,6 +1005,17 @@ 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();
|
int current_size = this->m_responseBody.tellp();
|
||||||
|
|
||||||
|
std::set<std::string> &bi = this->m_rules->m_responseBodyTypeToBeInspected;
|
||||||
|
auto t = bi.find(*m_responseContentType);
|
||||||
|
if (t == bi.end() && bi.empty() == false) {
|
||||||
|
#ifndef NO_LOGS
|
||||||
|
debug(4, "Not appending response body. " \
|
||||||
|
"Response Content-Type is " + *m_responseContentType + \
|
||||||
|
". It is not marked to be inspected.");
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef NO_LOGS
|
#ifndef NO_LOGS
|
||||||
debug(9, "Appending response body: " + std::to_string(len + current_size)
|
debug(9, "Appending response body: " + std::to_string(len + current_size)
|
||||||
+ " bytes. Limit set to: " +
|
+ " bytes. Limit set to: " +
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
%define parse.assert
|
%define parse.assert
|
||||||
%code requires
|
%code requires
|
||||||
{
|
{
|
||||||
# include <string>
|
#include <string>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
namespace ModSecurity {
|
namespace ModSecurity {
|
||||||
namespace Parser {
|
namespace Parser {
|
||||||
@ -601,6 +602,16 @@ expression:
|
|||||||
| CONFIG_DIR_PCRE_MATCH_LIMIT_RECURSION
|
| CONFIG_DIR_PCRE_MATCH_LIMIT_RECURSION
|
||||||
| CONFIG_DIR_PCRE_MATCH_LIMIT
|
| CONFIG_DIR_PCRE_MATCH_LIMIT
|
||||||
| CONGIG_DIR_RESPONSE_BODY_MP
|
| CONGIG_DIR_RESPONSE_BODY_MP
|
||||||
|
{
|
||||||
|
std::istringstream buf($1);
|
||||||
|
std::istream_iterator<std::string> beg(buf), end;
|
||||||
|
std::set<std::string> tokens(beg, end);
|
||||||
|
for (std::set<std::string>::iterator it=tokens.begin();
|
||||||
|
it!=tokens.end(); ++it)
|
||||||
|
{
|
||||||
|
driver.m_responseBodyTypeToBeInspected.insert(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
| CONGIG_DIR_SEC_TMP_DIR
|
| CONGIG_DIR_SEC_TMP_DIR
|
||||||
| CONGIG_DIR_SEC_DATA_DIR
|
| CONGIG_DIR_SEC_DATA_DIR
|
||||||
| CONGIG_DIR_SEC_ARG_SEP
|
| CONGIG_DIR_SEC_ARG_SEP
|
||||||
|
@ -259,7 +259,7 @@ CONFIG_DIR_UNICODE_MAP_FILE (?i:SecUnicodeMapFile)
|
|||||||
%{ /* Other configurations */ %}
|
%{ /* Other configurations */ %}
|
||||||
{CONFIG_DIR_PCRE_MATCH_LIMIT_RECURSION}[ ]{CONFIG_VALUE_NUMBER} { return yy::seclang_parser::make_CONFIG_DIR_PCRE_MATCH_LIMIT_RECURSION(strchr(yytext, ' ') + 1, *driver.loc.back()); }
|
{CONFIG_DIR_PCRE_MATCH_LIMIT_RECURSION}[ ]{CONFIG_VALUE_NUMBER} { return yy::seclang_parser::make_CONFIG_DIR_PCRE_MATCH_LIMIT_RECURSION(strchr(yytext, ' ') + 1, *driver.loc.back()); }
|
||||||
{CONFIG_DIR_PCRE_MATCH_LIMIT}[ ]{CONFIG_VALUE_NUMBER} { return yy::seclang_parser::make_CONFIG_DIR_PCRE_MATCH_LIMIT(strchr(yytext, ' ') + 1, *driver.loc.back()); }
|
{CONFIG_DIR_PCRE_MATCH_LIMIT}[ ]{CONFIG_VALUE_NUMBER} { return yy::seclang_parser::make_CONFIG_DIR_PCRE_MATCH_LIMIT(strchr(yytext, ' ') + 1, *driver.loc.back()); }
|
||||||
{CONGIG_DIR_RESPONSE_BODY_MP}[ ]{FREE_TEXT_NEW_LINE} { return yy::seclang_parser::make_CONGIG_DIR_RESPONSE_BODY_MP(yytext, *driver.loc.back()); }
|
{CONGIG_DIR_RESPONSE_BODY_MP}[ ]{FREE_TEXT_NEW_LINE} { return yy::seclang_parser::make_CONGIG_DIR_RESPONSE_BODY_MP(strchr(yytext, ' ') + 1, *driver.loc.back()); }
|
||||||
{CONGIG_DIR_SEC_TMP_DIR}[ ]{CONFIG_VALUE_PATH} { return yy::seclang_parser::make_CONGIG_DIR_SEC_TMP_DIR(strchr(yytext, ' ') + 1, *driver.loc.back()); }
|
{CONGIG_DIR_SEC_TMP_DIR}[ ]{CONFIG_VALUE_PATH} { return yy::seclang_parser::make_CONGIG_DIR_SEC_TMP_DIR(strchr(yytext, ' ') + 1, *driver.loc.back()); }
|
||||||
{CONGIG_DIR_SEC_DATA_DIR}[ ]{CONFIG_VALUE_PATH} { return yy::seclang_parser::make_CONGIG_DIR_SEC_DATA_DIR(strchr(yytext, ' ') + 1, *driver.loc.back()); }
|
{CONGIG_DIR_SEC_DATA_DIR}[ ]{CONFIG_VALUE_PATH} { return yy::seclang_parser::make_CONGIG_DIR_SEC_DATA_DIR(strchr(yytext, ' ') + 1, *driver.loc.back()); }
|
||||||
{CONGIG_DIR_SEC_ARG_SEP}[ ]{FREE_TEXT_NEW_LINE} { return yy::seclang_parser::make_CONGIG_DIR_SEC_ARG_SEP(yytext, *driver.loc.back()); }
|
{CONGIG_DIR_SEC_ARG_SEP}[ ]{FREE_TEXT_NEW_LINE} { return yy::seclang_parser::make_CONGIG_DIR_SEC_ARG_SEP(yytext, *driver.loc.back()); }
|
||||||
|
@ -221,6 +221,13 @@ int Rules::merge(Driver *from) {
|
|||||||
this->requestBodyLimitAction = from->requestBodyLimitAction;
|
this->requestBodyLimitAction = from->requestBodyLimitAction;
|
||||||
this->responseBodyLimitAction = from->responseBodyLimitAction;
|
this->responseBodyLimitAction = from->responseBodyLimitAction;
|
||||||
|
|
||||||
|
for (std::set<std::string>::iterator
|
||||||
|
it=from->m_responseBodyTypeToBeInspected.begin();
|
||||||
|
it!=from->m_responseBodyTypeToBeInspected.end(); ++it)
|
||||||
|
{
|
||||||
|
m_responseBodyTypeToBeInspected.insert(*it);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* default Actions is something per configuration context, there is
|
* default Actions is something per configuration context, there is
|
||||||
|
87
test/test-cases/regression/config-response_type.json
Normal file
87
test/test-cases/regression/config-response_type.json
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"enabled":1,
|
||||||
|
"version_min":300000,
|
||||||
|
"title":"SecResponseBodyMimeType (1/x)",
|
||||||
|
"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",
|
||||||
|
"method":"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":"T \\(0\\) trim: \"no need.\""
|
||||||
|
},
|
||||||
|
"rules":[
|
||||||
|
"SecRuleEngine On",
|
||||||
|
"SecDebugLog \/tmp\/modsec_debug.log",
|
||||||
|
"SecDebugLogLevel 9",
|
||||||
|
"SecResponseBodyMimeType text\/plain text\/html text\/xml",
|
||||||
|
"SecRule RESPONSE_BODY \"@contains RESPONSE_CONTENT_TYPE\" \"id:9,pass,t:trim,phase:4\""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"enabled":1,
|
||||||
|
"version_min":300000,
|
||||||
|
"title":"SecResponseBodyMimeType (1/x)",
|
||||||
|
"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",
|
||||||
|
"method":"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":"T \\(0\\) trim: \"text/html\""
|
||||||
|
},
|
||||||
|
"rules":[
|
||||||
|
"SecRuleEngine On",
|
||||||
|
"SecDebugLog \/tmp\/modsec_debug.log",
|
||||||
|
"SecDebugLogLevel 9",
|
||||||
|
"SecResponseBodyMimeType application\/something",
|
||||||
|
"SecRule RESPONSE_BODY \"@contains RESPONSE_CONTENT_TYPE\" \"id:9,pass,t:trim,phase:4\""
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
Loading…
x
Reference in New Issue
Block a user