diff --git a/components/attachment-intakers/nginx_attachment/nginx_parser.cc b/components/attachment-intakers/nginx_attachment/nginx_parser.cc index 7d5f69c..7392e00 100755 --- a/components/attachment-intakers/nginx_attachment/nginx_parser.cc +++ b/components/attachment-intakers/nginx_attachment/nginx_parser.cc @@ -28,8 +28,8 @@ USE_DEBUG_FLAG(D_NGINX_ATTACHMENT_PARSER); Buffer NginxParser::tenant_header_key = Buffer(); static const Buffer proxy_ip_header_key("X-Forwarded-For", 15, Buffer::MemoryType::STATIC); +static const Buffer waf_tag_key("x-waf-tag", 9, Buffer::MemoryType::STATIC); static const Buffer source_ip("sourceip", 8, Buffer::MemoryType::STATIC); -bool is_keep_alive_ctx = getenv("SAAS_KEEP_ALIVE_HDR_NAME") != nullptr; map NginxParser::content_encodings = { {Buffer("identity"), CompressionType::NO_COMPRESSION}, @@ -178,70 +178,41 @@ getActivetenantAndProfile(const string &str, const string &deli = ",") } Maybe> -NginxParser::parseRequestHeaders(const Buffer &data, const unordered_set &ignored_headers) +NginxParser::parseRequestHeaders(const Buffer &data) { - auto maybe_parsed_headers = genHeaders(data); - if (!maybe_parsed_headers.ok()) return maybe_parsed_headers.passErr(); + auto parsed_headers = genHeaders(data); + if (!parsed_headers.ok()) return parsed_headers.passErr(); auto i_transaction_table = Singleton::Consume>::by(); - auto parsed_headers = maybe_parsed_headers.unpack(); - NginxAttachmentOpaque &opaque = i_transaction_table->getState(); - if (is_keep_alive_ctx || !ignored_headers.empty()) { - bool is_last_header_removed = false; - parsed_headers.erase( - remove_if( - parsed_headers.begin(), - parsed_headers.end(), - [&opaque, &is_last_header_removed, &ignored_headers](const HttpHeader &header) - { - string hdr_key = static_cast(header.getKey()); - string hdr_val = static_cast(header.getValue()); - if ( - opaque.setKeepAliveCtx(hdr_key, hdr_val) - || ignored_headers.find(hdr_key) != ignored_headers.end() - ) { - dbgTrace(D_NGINX_ATTACHMENT_PARSER) << "Header was removed from headers list: " << hdr_key; - if (header.isLastHeader()) { - dbgTrace(D_NGINX_ATTACHMENT_PARSER) << "Last header was removed from headers list"; - is_last_header_removed = true; - } - return true; - } - return false; - } - ), - parsed_headers.end() - ); - if (is_last_header_removed) { - dbgTrace(D_NGINX_ATTACHMENT_PARSER) << "Adjusting last header flag"; - if (!parsed_headers.empty()) parsed_headers.back().setIsLastHeader(); - } - } - - for (const HttpHeader &header : parsed_headers) { + for (const HttpHeader &header : *parsed_headers) { auto source_identifiers = getConfigurationWithDefault( UsersAllIdentifiersConfig(), "rulebase", "usersIdentifiers" ); source_identifiers.parseRequestHeaders(header); + + NginxAttachmentOpaque &opaque = i_transaction_table->getState(); opaque.addToSavedData( HttpTransactionData::req_headers, static_cast(header.getKey()) + ": " + static_cast(header.getValue()) + "\r\n" ); - if (NginxParser::tenant_header_key == header.getKey()) { + const auto &header_key = header.getKey(); + if (NginxParser::tenant_header_key == header_key) { dbgDebug(D_NGINX_ATTACHMENT_PARSER) << "Identified active tenant header. Key: " - << dumpHex(header.getKey()) + << dumpHex(header_key) << ", Value: " << dumpHex(header.getValue()); auto active_tenant_and_profile = getActivetenantAndProfile(header.getValue()); opaque.setSessionTenantAndProfile(active_tenant_and_profile[0], active_tenant_and_profile[1]); - } else if (proxy_ip_header_key == header.getKey()) { + } else if (proxy_ip_header_key == header_key) { source_identifiers.setXFFValuesToOpaqueCtx(header, UsersAllIdentifiersConfig::ExtractType::PROXYIP); + } else if (waf_tag_key == header_key) { + source_identifiers.setWafTagValuesToOpaqueCtx(header); } } diff --git a/components/attachment-intakers/nginx_attachment/user_identifiers_config.cc b/components/attachment-intakers/nginx_attachment/user_identifiers_config.cc index 6c4407e..8a75e04 100755 --- a/components/attachment-intakers/nginx_attachment/user_identifiers_config.cc +++ b/components/attachment-intakers/nginx_attachment/user_identifiers_config.cc @@ -282,39 +282,21 @@ isIpTrusted(const string &value, const vector &cidr_values) } Maybe -UsersAllIdentifiersConfig::parseXForwardedFor(const string &str, ExtractType type) const +UsersAllIdentifiersConfig::parseXForwardedFor(const string &str) const { vector header_values = split(str); + if (header_values.empty()) return genError("No IP found in the xff header list"); vector xff_values = getHeaderValuesFromConfig("x-forwarded-for"); vector cidr_values(xff_values.begin(), xff_values.end()); - string last_valid_ip; - for (auto it = header_values.rbegin(); it != header_values.rend() - 1; ++it) { - if (!IPAddr::createIPAddr(*it).ok()) { - dbgWarning(D_NGINX_ATTACHMENT_PARSER) << "Invalid IP address found in the xff header IPs list: " << *it; - if (last_valid_ip.empty()) { - return genError("Invalid IP address"); - } - return last_valid_ip; + for (const string &value : header_values) { + if (!IPAddr::createIPAddr(value).ok()) { + dbgWarning(D_NGINX_ATTACHMENT_PARSER) << "Invalid IP address found in the xff header IPs list: " << value; + return genError("Invalid IP address"); } - last_valid_ip = *it; - if (type == ExtractType::PROXYIP) continue; - if (!isIpTrusted(*it, cidr_values)) { - dbgDebug(D_NGINX_ATTACHMENT_PARSER) << "Found untrusted IP in the xff header IPs list: " << *it; - return *it; - } - } - - if (!IPAddr::createIPAddr(header_values[0]).ok()) { - dbgWarning(D_NGINX_ATTACHMENT_PARSER) - << "Invalid IP address found in the xff header IPs list: " - << header_values[0]; - if (last_valid_ip.empty()) { - return genError("No Valid Ip address was found"); - } - return last_valid_ip; + if (!isIpTrusted(value, cidr_values)) return genError("Untrusted Ip found"); } return header_values[0]; @@ -330,7 +312,9 @@ UsersAllIdentifiersConfig::setXFFValuesToOpaqueCtx(const HttpHeader &header, Ext return; } NginxAttachmentOpaque &opaque = i_transaction_table->getState(); - auto value = parseXForwardedFor(header.getValue(), type); + opaque.setSavedData(HttpTransactionData::xff_vals_ctx, header.getValue()); + dbgTrace(D_NGINX_ATTACHMENT_PARSER) << "xff found, value from header: " << static_cast(header.getValue()); + auto value = parseXForwardedFor(header.getValue()); if (!value.ok()) { dbgTrace(D_NGINX_ATTACHMENT_PARSER) << "Could not extract source identifier from X-Forwarded-For header"; return; @@ -339,13 +323,8 @@ UsersAllIdentifiersConfig::setXFFValuesToOpaqueCtx(const HttpHeader &header, Ext if (type == ExtractType::SOURCEIDENTIFIER) { opaque.setSourceIdentifier(header.getKey(), value.unpack()); dbgDebug(D_NGINX_ATTACHMENT_PARSER) - << "Added source identifier from XFF header" + << "Added source identifir to XFF " << value.unpack(); - opaque.setSavedData(HttpTransactionData::xff_vals_ctx, header.getValue()); - opaque.setSavedData(HttpTransactionData::source_identifier, value.unpack()); - dbgTrace(D_NGINX_ATTACHMENT_PARSER) - << "XFF found, set ctx with value from header: " - << static_cast(header.getValue()); } else { opaque.setSavedData(HttpTransactionData::proxy_ip_ctx, value.unpack()); } @@ -366,6 +345,24 @@ UsersAllIdentifiersConfig::setCustomHeaderToOpaqueCtx(const HttpHeader &header) return; } +void +UsersAllIdentifiersConfig::setWafTagValuesToOpaqueCtx(const HttpHeader &header) const +{ + auto i_transaction_table = Singleton::Consume>::by(); + if (!i_transaction_table || !i_transaction_table->hasState()) { + dbgDebug(D_NGINX_ATTACHMENT_PARSER) << "Can't get the transaction table"; + return; + } + + NginxAttachmentOpaque &opaque = i_transaction_table->getState(); + opaque.setSavedData(HttpTransactionData::waf_tag_ctx, static_cast(header.getValue())); + + dbgDebug(D_NGINX_ATTACHMENT_PARSER) + << "Added waf tag to context: " + << static_cast(header.getValue()); + return; +} + Maybe UsersAllIdentifiersConfig::parseCookieElement( const string::const_iterator &start, diff --git a/components/include/generic_rulebase/evaluators/http_transaction_data_eval.h b/components/include/generic_rulebase/evaluators/http_transaction_data_eval.h index e9fb041..d8d1909 100755 --- a/components/include/generic_rulebase/evaluators/http_transaction_data_eval.h +++ b/components/include/generic_rulebase/evaluators/http_transaction_data_eval.h @@ -45,6 +45,19 @@ private: std::string host; }; +class EqualWafTag : public EnvironmentEvaluator, Singleton::Consume +{ +public: +EqualWafTag(const std::vector ¶ms); + + static std::string getName() { return "EqualWafTag"; } + + Maybe evalVariable() const override; + +private: + std::string waf_tag; +}; + class EqualListeningIP : public EnvironmentEvaluator, Singleton::Consume { public: diff --git a/components/include/http_transaction_data.h b/components/include/http_transaction_data.h index 680613f..9ccc9e1 100755 --- a/components/include/http_transaction_data.h +++ b/components/include/http_transaction_data.h @@ -137,6 +137,7 @@ public: static const std::string source_identifier; static const std::string proxy_ip_ctx; static const std::string xff_vals_ctx; + static const std::string waf_tag_ctx; static const CompressionType default_response_content_encoding; diff --git a/components/include/user_identifiers_config.h b/components/include/user_identifiers_config.h index d5921d6..aed9a3a 100755 --- a/components/include/user_identifiers_config.h +++ b/components/include/user_identifiers_config.h @@ -30,6 +30,7 @@ public: void parseRequestHeaders(const HttpHeader &header) const; std::vector getHeaderValuesFromConfig(const std::string &header_key) const; void setXFFValuesToOpaqueCtx(const HttpHeader &header, ExtractType type) const; + void setWafTagValuesToOpaqueCtx(const HttpHeader &header) const; private: class UsersIdentifiersConfig @@ -58,7 +59,7 @@ private: const std::string::const_iterator &end, const std::string &key) const; Buffer extractKeyValueFromCookie(const std::string &cookie_value, const std::string &key) const; - Maybe parseXForwardedFor(const std::string &str, ExtractType type) const; + Maybe parseXForwardedFor(const std::string &str) const; std::vector user_identifiers; }; diff --git a/components/utils/generic_rulebase/evaluators/http_transaction_data_eval.cc b/components/utils/generic_rulebase/evaluators/http_transaction_data_eval.cc index d6560fb..194914f 100644 --- a/components/utils/generic_rulebase/evaluators/http_transaction_data_eval.cc +++ b/components/utils/generic_rulebase/evaluators/http_transaction_data_eval.cc @@ -103,6 +103,35 @@ WildcardHost::evalVariable() const return lower_host_ctx == lower_host; } +EqualWafTag::EqualWafTag(const vector ¶ms) +{ + if (params.size() != 1) reportWrongNumberOfParams("EqualWafTag", params.size(), 1, 1); + waf_tag = params[0]; +} + +Maybe +EqualWafTag::evalVariable() const +{ + I_Environment *env = Singleton::Consume::by(); + auto maybe_waf_tag_ctx = env->get(HttpTransactionData::waf_tag_ctx); + + if (!maybe_waf_tag_ctx.ok()) + { + dbgTrace(D_RULEBASE_CONFIG) << "didnt find waf tag in current context"; + return false; + } + + auto waf_tag_ctx = maybe_waf_tag_ctx.unpack(); + + dbgTrace(D_RULEBASE_CONFIG) + << "trying to match waf tag context with its corresponding waf tag: " + << waf_tag_ctx + << ". Matcher waf tag: " + << waf_tag; + + return waf_tag_ctx == waf_tag; +} + EqualListeningIP::EqualListeningIP(const vector ¶ms) { if (params.size() != 1) reportWrongNumberOfParams("EqualListeningIP", params.size(), 1, 1); diff --git a/components/utils/generic_rulebase/generic_rulebase.cc b/components/utils/generic_rulebase/generic_rulebase.cc index c7f98de..228d5d3 100644 --- a/components/utils/generic_rulebase/generic_rulebase.cc +++ b/components/utils/generic_rulebase/generic_rulebase.cc @@ -80,6 +80,7 @@ GenericRulebase::Impl::preload() addMatcher(); addMatcher(); addMatcher(); + addMatcher(); addMatcher(); addMatcher(); addMatcher(); diff --git a/components/utils/http_transaction_data/http_transaction_data.cc b/components/utils/http_transaction_data/http_transaction_data.cc index 0025619..31714f3 100644 --- a/components/utils/http_transaction_data/http_transaction_data.cc +++ b/components/utils/http_transaction_data/http_transaction_data.cc @@ -53,6 +53,7 @@ const string HttpTransactionData::req_body = "transaction_request_body const string HttpTransactionData::source_identifier = "sourceIdentifiers"; const string HttpTransactionData::proxy_ip_ctx = "proxy_ip"; const string HttpTransactionData::xff_vals_ctx = "xff_vals"; +const string HttpTransactionData::waf_tag_ctx = "waf_tag"; const CompressionType HttpTransactionData::default_response_content_encoding = CompressionType::NO_COMPRESSION;