From cb722c74b9c39d2ffac4da7248e7fed85dfb5b59 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle Date: Wed, 22 Jul 2015 01:48:20 -0300 Subject: [PATCH] Adds support to REQUEST_HEADERS{_NAMES} and RESPONSE_HEADERS{_NAMES} vars --- headers/modsecurity/assay.h | 4 +- src/assay.cc | 25 +++----- .../regression/variable-REQUEST_HEADERS.json | 63 +++++++++++++++++++ .../variable-REQUEST_HEADERS_NAMES.json | 63 +++++++++++++++++++ .../regression/variable-RESPONSE_HEADERS.json | 63 +++++++++++++++++++ .../variable-RESPONSE_HEADERS_NAMES.json | 63 +++++++++++++++++++ 6 files changed, 264 insertions(+), 17 deletions(-) create mode 100644 test/test-cases/regression/variable-REQUEST_HEADERS.json create mode 100644 test/test-cases/regression/variable-REQUEST_HEADERS_NAMES.json create mode 100644 test/test-cases/regression/variable-RESPONSE_HEADERS.json create mode 100644 test/test-cases/regression/variable-RESPONSE_HEADERS_NAMES.json diff --git a/headers/modsecurity/assay.h b/headers/modsecurity/assay.h index c7abe9a5..5973d9cc 100644 --- a/headers/modsecurity/assay.h +++ b/headers/modsecurity/assay.h @@ -209,8 +209,8 @@ class Assay { std::string *m_namesArgs; std::string *m_namesArgsPost; std::string *m_namesArgsGet; - std::string m_namesResponse; - std::string m_namesRequest; + std::string *m_requestHeadersNames; + std::string *m_responseHeadersNames; double m_ARGScombinedSize; /** TODO: Support to save double in the storage. */ std::string *m_ARGScombinedSizeStr; diff --git a/src/assay.cc b/src/assay.cc index 8b89d84b..098f27f2 100644 --- a/src/assay.cc +++ b/src/assay.cc @@ -99,6 +99,8 @@ Assay::Assay(ModSecurity *ms, Rules *rules) m_namesArgsPost(NULL), m_namesArgsGet(NULL), m_requestBodyType(UnknownFormat), + m_requestHeadersNames(NULL), + m_responseHeadersNames(NULL), start(std::chrono::system_clock::now()), m_ms(ms) { id = std::to_string(this->timeStamp) + \ @@ -113,6 +115,12 @@ Assay::Assay(ModSecurity *ms, Rules *rules) this->m_namesArgsPost = resolve_variable_first("ARGS_POST_NAMES"); store_variable("ARGS_GET_NAMES", std::string("")); this->m_namesArgsGet = resolve_variable_first("ARGS_GET_NAMES"); + store_variable("REQUEST_HEADERS_NAMES", std::string("")); + this->m_requestHeadersNames = resolve_variable_first( + "REQUEST_HEADERS_NAMES"); + store_variable("RESPONSE_HEADERS_NAMES", std::string("")); + this->m_responseHeadersNames = resolve_variable_first( + "RESPONSE_HEADERS_NAMES"); this->debug(4, "Initialising transaction"); } @@ -318,14 +326,7 @@ int Assay::processRequestHeaders() { */ int Assay::addRequestHeader(const std::string& key, const std::string& value) { - std::string *names = resolve_variable_first("REQUEST_HEADERS_NAMES"); - - if (names == NULL) { - this->store_variable("REQUEST_HEADERS_NAMES", m_namesRequest); - m_namesRequest = key; - } else { - m_namesRequest = m_namesRequest + " " + key; - } + m_requestHeadersNames->assign(*m_requestHeadersNames + " " + key); this->store_variable("REQUEST_HEADERS:" + key, value); @@ -652,13 +653,7 @@ int Assay::processResponseHeaders() { int Assay::addResponseHeader(const std::string& key, const std::string& value) { std::string *names = resolve_variable_first("RESPONSE_HEADERS_NAMES"); - - if (names == NULL) { - this->store_variable("RESPONSE_HEADERS_NAMES", m_namesResponse); - m_namesRequest = key; - } else { - m_namesRequest = m_namesRequest + " " + key; - } + m_responseHeadersNames->assign(*m_responseHeadersNames + " " + key); this->store_variable("RESPONSE_HEADERS:" + key, value); diff --git a/test/test-cases/regression/variable-REQUEST_HEADERS.json b/test/test-cases/regression/variable-REQUEST_HEADERS.json new file mode 100644 index 00000000..6eb004f0 --- /dev/null +++ b/test/test-cases/regression/variable-REQUEST_HEADERS.json @@ -0,0 +1,63 @@ +[ + { + "enabled":1, + "version_min":300000, + "title":"Testing Variables :: REQUEST_HEADERS", + "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":[ + "no need." + ] + }, + "expected":{ + "debug_log":"Target value: \"localhost\" \\(Variable: REQUEST_HEADERS:Host\\)" + }, + "rules":[ + "SecRuleEngine On", + "SecDebugLog \/tmp\/modsec_debug.log", + "SecDebugLogLevel 9", + "SecRule REQUEST_HEADERS \"@contains small_text_file.txt\" \"phase:3,pass,t:trim\"" + ] + } +] \ No newline at end of file diff --git a/test/test-cases/regression/variable-REQUEST_HEADERS_NAMES.json b/test/test-cases/regression/variable-REQUEST_HEADERS_NAMES.json new file mode 100644 index 00000000..a89d00f2 --- /dev/null +++ b/test/test-cases/regression/variable-REQUEST_HEADERS_NAMES.json @@ -0,0 +1,63 @@ +[ + { + "enabled":1, + "version_min":300000, + "title":"Testing Variables :: REQUEST_HEADERS_NAMES", + "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":[ + "no need." + ] + }, + "expected":{ + "debug_log":"Target value: \"Expect Content-Type Accept User-Agent Content-Length Host\" \\(Variable: REQUEST_HEADERS_NAMES\\)" + }, + "rules":[ + "SecRuleEngine On", + "SecDebugLog \/tmp\/modsec_debug.log", + "SecDebugLogLevel 9", + "SecRule REQUEST_HEADERS_NAMES \"@contains small_text_file.txt\" \"phase:3,pass,t:trim\"" + ] + } +] \ No newline at end of file diff --git a/test/test-cases/regression/variable-RESPONSE_HEADERS.json b/test/test-cases/regression/variable-RESPONSE_HEADERS.json new file mode 100644 index 00000000..891c51d4 --- /dev/null +++ b/test/test-cases/regression/variable-RESPONSE_HEADERS.json @@ -0,0 +1,63 @@ +[ + { + "enabled":1, + "version_min":300000, + "title":"Testing Variables :: RESPONSE_HEADERS", + "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":[ + "no need." + ] + }, + "expected":{ + "debug_log":"Target value: \"Mon, 13 Jul 2015 20:02:41 GMT\" \\(Variable: RESPONSE_HEADERS:Date\\)" + }, + "rules":[ + "SecRuleEngine On", + "SecDebugLog \/tmp\/modsec_debug.log", + "SecDebugLogLevel 9", + "SecRule RESPONSE_HEADERS \"@contains small_text_file.txt\" \"phase:3,pass,t:trim\"" + ] + } +] \ No newline at end of file diff --git a/test/test-cases/regression/variable-RESPONSE_HEADERS_NAMES.json b/test/test-cases/regression/variable-RESPONSE_HEADERS_NAMES.json new file mode 100644 index 00000000..6e3d1503 --- /dev/null +++ b/test/test-cases/regression/variable-RESPONSE_HEADERS_NAMES.json @@ -0,0 +1,63 @@ +[ + { + "enabled":1, + "version_min":300000, + "title":"Testing Variables :: RESPONSE_HEADERS_NAMES", + "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":[ + "no need." + ] + }, + "expected":{ + "debug_log":"Target value: \"Content-Type Last-Modified Date\" \\(Variable: RESPONSE_HEADERS_NAMES\\)" + }, + "rules":[ + "SecRuleEngine On", + "SecDebugLog \/tmp\/modsec_debug.log", + "SecDebugLogLevel 9", + "SecRule RESPONSE_HEADERS_NAMES \"@contains small_text_file.txt\" \"phase:3,pass,t:trim\"" + ] + } +] \ No newline at end of file