diff --git a/CHANGES b/CHANGES index 4c191f52..9f4c746e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ v3.x.y - YYYY-MMM-DD (to be released) ------------------------------------- + - Handle URI received with uri-fragment + [@martinhsv] - Having ARGS_NAMES, variables proxied [@zimmerle, @martinhsv, @KaNikita] - Use explicit path for cross-compile environments. diff --git a/src/transaction.cc b/src/transaction.cc index b6872596..bae7c4ca 100644 --- a/src/transaction.cc +++ b/src/transaction.cc @@ -445,11 +445,21 @@ int Transaction::processURI(const char *uri, const char *method, m_httpVersion = http_version; m_uri = uri; std::string uri_s(uri); - m_uri_decoded = utils::uri_decode(uri); - size_t pos = m_uri_decoded.find("?"); - size_t pos_raw = uri_s.find("?"); - size_t var_size = pos_raw; + // any uri-fragment that was received should only be retained in + // - m_uri + // - m_variableRequestURIRaw + // - m_variableRequestLine + size_t pos_raw_fragment = uri_s.find("#"); + if (pos_raw_fragment != std::string::npos) { + uri_s = uri_s.substr(0, pos_raw_fragment); + } + + size_t pos_raw_query = uri_s.find("?"); + + m_uri_decoded = utils::uri_decode(uri_s); + + size_t var_size = pos_raw_query; m_variableRequestMethod.set(method, 0); @@ -462,28 +472,28 @@ int Transaction::processURI(const char *uri, const char *method, m_variableOffset + requestLine.size() + 1); - - if (pos != std::string::npos) { + size_t pos_query = m_uri_decoded.find("?"); + if (pos_query != std::string::npos) { m_uri_no_query_string_decoded = std::unique_ptr( - new std::string(m_uri_decoded, 0, pos)); + new std::string(m_uri_decoded, 0, pos_query)); } else { m_uri_no_query_string_decoded = std::unique_ptr( new std::string(m_uri_decoded)); } - if (pos_raw != std::string::npos) { - std::string qry = std::string(uri_s, pos_raw + 1, - uri_s.length() - (pos_raw + 1)); - m_variableQueryString.set(qry, pos_raw + 1 + if (pos_raw_query != std::string::npos) { + std::string qry = std::string(uri_s, pos_raw_query + 1, + uri_s.length() - (pos_raw_query + 1)); + m_variableQueryString.set(qry, pos_raw_query + 1 + std::string(method).size() + 1); } std::string path_info; - if (pos == std::string::npos) { + if (pos_query == std::string::npos) { path_info = std::string(m_uri_decoded, 0); } else { - path_info = std::string(m_uri_decoded, 0, pos); + path_info = std::string(m_uri_decoded, 0, pos_query); } if (var_size == std::string::npos) { var_size = uri_s.size(); @@ -495,7 +505,6 @@ int Transaction::processURI(const char *uri, const char *method, strlen(method) + 1, var_size); - size_t offset = path_info.find_last_of("/\\"); if (offset != std::string::npos && path_info.length() > offset + 1) { std::string basename = std::string(path_info, offset + 1, diff --git a/test/test-cases/regression/variable-ARGS_GET.json b/test/test-cases/regression/variable-ARGS_GET.json index b1be844e..dde6d690 100644 --- a/test/test-cases/regression/variable-ARGS_GET.json +++ b/test/test-cases/regression/variable-ARGS_GET.json @@ -2,7 +2,7 @@ { "enabled":1, "version_min":300000, - "title":"Testing Variables :: ARGS_GET (1/5)", + "title":"Testing Variables :: ARGS_GET (1/6)", "client":{ "ip":"200.249.12.31", "port":123 @@ -41,7 +41,7 @@ { "enabled":1, "version_min":300000, - "title":"Testing Variables :: ARGS_GET (2/5)", + "title":"Testing Variables :: ARGS_GET (2/6)", "client":{ "ip":"200.249.12.31", "port":123 @@ -80,7 +80,7 @@ { "enabled":1, "version_min":300000, - "title":"Testing Variables :: ARGS_GET (3/5)", + "title":"Testing Variables :: ARGS_GET (3/6)", "client":{ "ip":"200.249.12.31", "port":123 @@ -119,7 +119,7 @@ { "enabled":1, "version_min":300000, - "title":"Testing Variables :: ARGS_GET (4/5)", + "title":"Testing Variables :: ARGS_GET (4/6)", "client":{ "ip":"200.249.12.31", "port":123 @@ -158,7 +158,7 @@ { "enabled":1, "version_min":300000, - "title":"Testing Variables :: ARGS_GET (5/5)", + "title":"Testing Variables :: ARGS_GET (5/6)", "client":{ "ip":"200.249.12.31", "port":123 @@ -193,6 +193,46 @@ "SecRuleEngine On", "SecRule ARGS_GET \"@rx ^othervalue$ \" \"id:1,pass,t:none\"" ] + }, + { + "enabled":1, + "version_min":300000, + "title":"Testing Variables :: ARGS_GET (6/6)", + "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&second_key=other_value#urifrag", + "method":"GET", + "http_version":1.1 + }, + "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":{ + "http_code": 403 + }, + "rules":[ + "SecRuleEngine On", + "SecRule ARGS_GET \"@streq other_value\" \"id:1,phase:1,deny,status:403\"" + ] } ] diff --git a/test/test-cases/regression/variable-QUERY_STRING.json b/test/test-cases/regression/variable-QUERY_STRING.json index a2246a1b..02fc497b 100644 --- a/test/test-cases/regression/variable-QUERY_STRING.json +++ b/test/test-cases/regression/variable-QUERY_STRING.json @@ -39,5 +39,85 @@ "SecRuleEngine On", "SecRule QUERY_STRING \"@contains test \" \"id:1,phase:3,pass,t:trim\"" ] + }, + { + "enabled":1, + "version_min":300000, + "title":"Testing Variables :: QUERY_STRING (URI contains fragment)", + "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#urifrag", + "method":"GET", + "http_version":1.1 + }, + "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":{ + "http_code": 403 + }, + "rules":[ + "SecRuleEngine On", + "SecRule QUERY_STRING \"!@contains urifrag\" \"id:1,phase:1,deny,status:403\"" + ] + }, + { + "enabled":1, + "version_min":300000, + "title":"Testing Variables :: QUERY_STRING (URI contains fragment)", + "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":"/one/two/testpost.php#urifrag", + "method":"GET", + "http_version":1.1 + }, + "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":{ + "http_code": 403 + }, + "rules":[ + "SecRuleEngine On", + "SecRule QUERY_STRING \"@eq 0\" \"id:1,phase:1,t:length,deny,status:403\"" + ] } ] diff --git a/test/test-cases/regression/variable-REQUEST_LINE.json b/test/test-cases/regression/variable-REQUEST_LINE.json index 83b493bb..586f0c31 100644 --- a/test/test-cases/regression/variable-REQUEST_LINE.json +++ b/test/test-cases/regression/variable-REQUEST_LINE.json @@ -38,6 +38,86 @@ "SecRuleEngine On", "SecRule REQUEST_LINE \"@contains test \" \"id:1,pass,t:trim\"" ] + }, + { + "enabled":1, + "version_min":300000, + "title":"Testing Variables :: REQUEST_LINE (with URI fragment)", + "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#urifrag", + "method":"GET", + "http_version":1.1 + }, + "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":{ + "http_code": 403 + }, + "rules":[ + "SecRuleEngine On", + "SecRule REQUEST_LINE \"@contains urifrag\" \"id:1,phase:1,deny,status:403\"" + ] + }, + { + "enabled":1, + "version_min":300000, + "title":"Testing Variables :: REQUEST_URI_RAW (with URI fragment)", + "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":"/one/two/testpost.php#urifrag", + "method":"GET", + "http_version":1.1 + }, + "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":{ + "http_code": 403 + }, + "rules":[ + "SecRuleEngine On", + "SecRule REQUEST_URI_RAW \"@contains urifrag\" \"id:1,phase:1,deny,status:403\"" + ] } ] diff --git a/test/test-cases/regression/variable-REQUEST_URI.json b/test/test-cases/regression/variable-REQUEST_URI.json index 8336c9fa..795ce29b 100644 --- a/test/test-cases/regression/variable-REQUEST_URI.json +++ b/test/test-cases/regression/variable-REQUEST_URI.json @@ -38,6 +38,86 @@ "SecRuleEngine On", "SecRule REQUEST_URI \"@contains test \" \"id:1,pass,t:trim\"" ] + }, + { + "enabled":1, + "version_min":300000, + "title":"Testing Variables :: REQUEST_URI (with URI fragment)", + "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#urifrag", + "method":"GET", + "http_version":1.1 + }, + "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":{ + "http_code": 403 + }, + "rules":[ + "SecRuleEngine On", + "SecRule REQUEST_URI \"!@contains urifrag\" \"id:1,phase:1,deny,status:403\"" + ] + }, + { + "enabled":1, + "version_min":300000, + "title":"Testing Variables :: REQUEST_URI (with URI fragment)", + "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":"/one/two/testpost.php#urifrag", + "method":"GET", + "http_version":1.1 + }, + "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":{ + "http_code": 403 + }, + "rules":[ + "SecRuleEngine On", + "SecRule REQUEST_URI \"!@contains urifrag\" \"id:1,phase:1,deny,status:403\"" + ] } ] diff --git a/test/test-cases/regression/variable-REQUEST_URI_RAW.json b/test/test-cases/regression/variable-REQUEST_URI_RAW.json index d4ea9b37..09fff33c 100644 --- a/test/test-cases/regression/variable-REQUEST_URI_RAW.json +++ b/test/test-cases/regression/variable-REQUEST_URI_RAW.json @@ -38,6 +38,86 @@ "SecRuleEngine On", "SecRule REQUEST_URI_RAW \"@contains test \" \"id:1,pass,t:trim\"" ] + }, + { + "enabled":1, + "version_min":300000, + "title":"Testing Variables :: REQUEST_URI_RAW (with URI fragment)", + "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#urifrag", + "method":"GET", + "http_version":1.1 + }, + "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":{ + "http_code": 403 + }, + "rules":[ + "SecRuleEngine On", + "SecRule REQUEST_URI_RAW \"@contains urifrag\" \"id:1,phase:1,deny,status:403\"" + ] + }, + { + "enabled":1, + "version_min":300000, + "title":"Testing Variables :: REQUEST_URI_RAW (with URI fragment)", + "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":"/one/two/testpost.php#urifrag", + "method":"GET", + "http_version":1.1 + }, + "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":{ + "http_code": 403 + }, + "rules":[ + "SecRuleEngine On", + "SecRule REQUEST_URI_RAW \"@contains urifrag\" \"id:1,phase:1,deny,status:403\"" + ] } ]