Adds support to SecResponseBodyMimeType

This commit is contained in:
Felipe Zimmerle 2015-12-24 11:53:43 -03:00
parent c2d9a153cb
commit decf04d264
7 changed files with 141 additions and 3 deletions

View File

@ -194,6 +194,7 @@ class Assay {
std::string *m_namesArgsGet;
std::string *m_requestHeadersNames;
std::string *m_responseHeadersNames;
std::string *m_responseContentType;
double m_ARGScombinedSize;
/** TODO: Support to save double in the storage. */
std::string *m_ARGScombinedSizeStr;

View File

@ -201,6 +201,7 @@ class RulesProperties {
std::string audit_log_path;
std::string audit_log_parts;
std::list<std::string> components;
std::set<std::string> m_responseBodyTypeToBeInspected;
DebugLog *m_debugLog;

View File

@ -105,6 +105,7 @@ Assay::Assay(ModSecurity *ms, Rules *rules, void *logCbData)
m_requestBodyType(UnknownFormat),
m_requestHeadersNames(NULL),
m_responseHeadersNames(NULL),
m_responseContentType(NULL),
m_marker(""),
start(cpu_seconds()),
m_logCbData(logCbData),
@ -127,6 +128,10 @@ Assay::Assay(ModSecurity *ms, Rules *rules, void *logCbData)
m_collections.store("RESPONSE_HEADERS_NAMES", std::string(""));
this->m_responseHeadersNames = m_collections.resolveFirst(
"RESPONSE_HEADERS_NAMES");
m_collections.store("RESPONSE_CONTENT_TYPE", std::string(""));
this->m_responseContentType = m_collections.resolveFirst(
"RESPONSE_CONTENT_TYPE");
#ifndef NO_LOGS
this->debug(4, "Initialising transaction");
@ -860,7 +865,7 @@ int Assay::addResponseHeader(const std::string& key,
this->m_collections.store("RESPONSE_HEADERS:" + key, value);
if (tolower(key) == "content-type") {
this->m_collections.store("RESPONSE_CONTENT_TYPE", value);
this->m_responseContentType->assign(value);
}
return 1;
}
@ -951,6 +956,21 @@ int Assay::processResponseBody() {
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) {
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 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
debug(9, "Appending response body: " + std::to_string(len + current_size)
+ " bytes. Limit set to: " +

View File

@ -8,7 +8,8 @@
%define parse.assert
%code requires
{
# include <string>
#include <string>
#include <iterator>
namespace ModSecurity {
namespace Parser {
@ -601,6 +602,16 @@ expression:
| CONFIG_DIR_PCRE_MATCH_LIMIT_RECURSION
| CONFIG_DIR_PCRE_MATCH_LIMIT
| 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_DATA_DIR
| CONGIG_DIR_SEC_ARG_SEP

View File

@ -259,7 +259,7 @@ CONFIG_DIR_UNICODE_MAP_FILE (?i:SecUnicodeMapFile)
%{ /* 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}[ ]{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_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()); }

View File

@ -221,6 +221,13 @@ int Rules::merge(Driver *from) {
this->requestBodyLimitAction = from->requestBodyLimitAction;
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

View 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\""
]
}
]