mirror of
https://github.com/openappsec/openappsec.git
synced 2026-01-17 16:00:26 +03:00
Jan 06 2026 dev (#387)
* sync code * update code to support brotli * update code to support brotli * update code to support brotli * sync code * fix findBrotli * sync code * sync code * sync code * sync code --------- Co-authored-by: Ned Wright <nedwright@proton.me> Co-authored-by: Daniel Eisenberg <danielei@checkpoint.com>
This commit is contained in:
@@ -21,13 +21,13 @@
|
||||
#include <vector>
|
||||
|
||||
#include "config.h"
|
||||
#include "i_generic_rulebase.h"
|
||||
#include "i_first_tier_agg.h"
|
||||
#include "ips_entry.h"
|
||||
#include "ips_enums.h"
|
||||
#include "log_generator.h"
|
||||
#include "parsed_context.h"
|
||||
#include "pm_hook.h"
|
||||
#include "i_generic_rulebase.h"
|
||||
|
||||
#define DEFAULT_IPS_YIELD_COUNT 500
|
||||
|
||||
@@ -402,6 +402,7 @@ public:
|
||||
|
||||
LogTriggerConf getTrigger() const;
|
||||
|
||||
|
||||
std::set<ParameterBehavior>
|
||||
getBehavior(const std::unordered_map<std::string, std::set<std::string>> &exceptions_dict) const;
|
||||
|
||||
@@ -410,10 +411,21 @@ private:
|
||||
/// \param ips_state The IPS entry.
|
||||
ActionResults getAction(const IPSEntry &ips_state) const;
|
||||
|
||||
void sendLog(
|
||||
const Buffer &context_buffer,
|
||||
const IPSEntry &ips_state,
|
||||
const std::tuple<
|
||||
IPSSignatureSubTypes::SignatureAction,
|
||||
std::string, std::vector<std::string>
|
||||
> &override_action,
|
||||
bool is_prevent
|
||||
) const;
|
||||
|
||||
std::shared_ptr<CompleteSignature> signature;
|
||||
SignatureAction action;
|
||||
std::string trigger_id;
|
||||
std::string exception_id;
|
||||
mutable bool bSupressLog = false;
|
||||
};
|
||||
} // namespace IPSSignatureSubTypes
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "virtual_modifiers.h"
|
||||
#include "helper.h"
|
||||
#include "ips_common_types.h"
|
||||
#include "nginx_attachment_common.h"
|
||||
#include "nano_attachment_common.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -46,9 +46,9 @@ class IPSComp::Impl
|
||||
public Listener<HttpResponseBodyEvent>,
|
||||
public Listener<EndTransactionEvent>
|
||||
{
|
||||
static constexpr auto DROP = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP;
|
||||
static constexpr auto ACCEPT = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT;
|
||||
static constexpr auto INSPECT = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT;
|
||||
static constexpr auto DROP = ServiceVerdict::TRAFFIC_VERDICT_DROP;
|
||||
static constexpr auto ACCEPT = ServiceVerdict::TRAFFIC_VERDICT_ACCEPT;
|
||||
static constexpr auto INSPECT = ServiceVerdict::TRAFFIC_VERDICT_INSPECT;
|
||||
|
||||
class SigsFirstTierAgg
|
||||
{
|
||||
@@ -383,8 +383,8 @@ IPSComp::preload()
|
||||
registerExpectedResource<SnortSignaturesResource>("IPSSnortSigs", "protections");
|
||||
registerExpectedConfiguration<IPSConfiguration>("IPS", "IpsConfigurations");
|
||||
registerExpectedConfiguration<uint>("IPS", "Max Field Size");
|
||||
registerExpectedConfiguration<IPSSignatures>("IPS", "IpsProtections");
|
||||
registerExpectedConfiguration<SnortSignatures>("IPSSnortSigs", "SnortProtections");
|
||||
registerExpectedConfigurationWithCache<IPSSignatures>("assetId", "IPS", "IpsProtections");
|
||||
registerExpectedConfigurationWithCache<SnortSignatures>("assetId", "IPSSnortSigs", "SnortProtections");
|
||||
registerExpectedConfigFile("ips", Config::ConfigFileType::Policy);
|
||||
registerExpectedConfigFile("ips", Config::ConfigFileType::Data);
|
||||
registerExpectedConfigFile("snort", Config::ConfigFileType::Policy);
|
||||
|
||||
@@ -321,6 +321,9 @@ SignatureAndAction::getAction(const IPSEntry &ips_state) const
|
||||
override_actions.insert(behavior.getValue());
|
||||
const string &override_id = behavior.getId();
|
||||
if (!override_id.empty()) override_ids.push_back(override_id);
|
||||
} else if(behavior.getKey() == BehaviorKey::LOG && behavior.getValue() == BehaviorValue::IGNORE) {
|
||||
dbgTrace(D_IPS) << "setting bSupressLog due to override behavior: " << behavior.getId();
|
||||
bSupressLog = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,8 +361,10 @@ set<ParameterBehavior>
|
||||
SignatureAndAction::getBehavior(const unordered_map<string, set<string>> &exceptions_dict) const
|
||||
{
|
||||
I_GenericRulebase *i_rulebase = Singleton::Consume<I_GenericRulebase>::by<IPSComp>();
|
||||
if (exception_id.empty()) return i_rulebase->getBehavior(exceptions_dict);
|
||||
|
||||
if (exception_id.empty()) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "No exception id provided, using default behavior";
|
||||
return i_rulebase->getBehavior(exceptions_dict);
|
||||
}
|
||||
return i_rulebase->getParameterException(exception_id).getBehavior(exceptions_dict);
|
||||
}
|
||||
|
||||
@@ -453,10 +458,25 @@ SignatureAndAction::isMatchedPrevent(const Buffer &context_buffer, const set<PMP
|
||||
return false;
|
||||
}
|
||||
|
||||
dbgDebug(D_IPS) << "Signature matched - sending log";
|
||||
bool is_prevent = get<0>(override_action) == IPSSignatureSubTypes::SignatureAction::PREVENT;
|
||||
if(bSupressLog) {
|
||||
dbgTrace(D_IPS) << "Signature matched - not sending log due to exception behavior";
|
||||
} else {
|
||||
sendLog(context_buffer, ips_state, override_action, is_prevent);
|
||||
}
|
||||
return is_prevent;
|
||||
}
|
||||
|
||||
void SignatureAndAction::sendLog(
|
||||
const Buffer &context_buffer,
|
||||
const IPSEntry &ips_state,
|
||||
const tuple<IPSSignatureSubTypes::SignatureAction, string, vector<string>> &override_action,
|
||||
bool is_prevent
|
||||
) const
|
||||
{
|
||||
dbgFlow(D_IPS) << "Signature matched - sending log";
|
||||
|
||||
auto trigger = getTrigger();
|
||||
bool is_prevent = get<0>(override_action) == IPSSignatureSubTypes::SignatureAction::PREVENT;
|
||||
|
||||
auto severity = signature->getSeverity() < IPSLevel::HIGH ? Severity::HIGH : Severity::CRITICAL;
|
||||
if (get<0>(override_action) == IPSSignatureSubTypes::SignatureAction::DETECT) severity = Severity::INFO;
|
||||
@@ -560,7 +580,7 @@ SignatureAndAction::isMatchedPrevent(const Buffer &context_buffer, const set<PMP
|
||||
uint res_size = res_body.ok() && trigger.isWebLogFieldActive(::res_body) ? res_body.unpack().size() : 0;
|
||||
if (req_size + res_size > max_size) {
|
||||
if (req_size + 500 > max_size) {
|
||||
res_size = std::min(500u, res_size);
|
||||
res_size = min(500u, res_size);
|
||||
req_size = max_size - res_size;
|
||||
} else {
|
||||
res_size = max_size - req_size;
|
||||
@@ -572,10 +592,8 @@ SignatureAndAction::isMatchedPrevent(const Buffer &context_buffer, const set<PMP
|
||||
log << LogField("waapOverride", get<1>(override_action));
|
||||
|
||||
if (!get<2>(override_action).empty()) log.addToOrigin(LogField("exceptionIdList", get<2>(override_action)));
|
||||
|
||||
log << LogField("securityAction", is_prevent ? "Prevent" : "Detect");
|
||||
|
||||
return is_prevent;
|
||||
log << LogField("securityAction", is_prevent ? "Prevent" : "Detect");
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -109,11 +109,11 @@ operator ==(const EventVerdict &first, const EventVerdict &second)
|
||||
return first.getVerdict() == second.getVerdict();
|
||||
}
|
||||
|
||||
const EventVerdict ComponentTest::inspect(ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT);
|
||||
const EventVerdict ComponentTest::inspect(ServiceVerdict::TRAFFIC_VERDICT_INSPECT);
|
||||
|
||||
const EventVerdict ComponentTest::accept(ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT);
|
||||
const EventVerdict ComponentTest::accept(ServiceVerdict::TRAFFIC_VERDICT_ACCEPT);
|
||||
|
||||
const EventVerdict ComponentTest::drop(ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP);
|
||||
const EventVerdict ComponentTest::drop(ServiceVerdict::TRAFFIC_VERDICT_DROP);
|
||||
|
||||
TEST_F(ComponentTest, check_init_fini_do_not_crush)
|
||||
{
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "generic_rulebase/generic_rulebase_context.h"
|
||||
#include "encryptor.h"
|
||||
#include "mock/mock_table.h"
|
||||
USE_DEBUG_FLAG(D_IPS);
|
||||
|
||||
using namespace testing;
|
||||
using namespace std;
|
||||
@@ -194,6 +195,101 @@ public:
|
||||
gen_ctx->activate();
|
||||
}
|
||||
|
||||
// Loads an exception with log: ignore behavior, as in the provided JSON
|
||||
void loadExceptionsIgnoreLog()
|
||||
{
|
||||
BasicRuleConfig::preload();
|
||||
registerExpectedConfiguration<ParameterException>("rulebase", "exception");
|
||||
|
||||
string test_config(
|
||||
"{"
|
||||
" \"rulebase\": {"
|
||||
" \"rulesConfig\": ["
|
||||
" {"
|
||||
" \"context\": \"All()\","
|
||||
" \"priority\": 1,"
|
||||
" \"ruleId\": \"5eaef0726765c30010bae8bb\","
|
||||
" \"ruleName\": \"Acme web API\","
|
||||
" \"assetId\": \"5e243effd858007660b758ad\","
|
||||
" \"assetName\": \"Acme Power API\","
|
||||
" \"parameters\": ["
|
||||
" {"
|
||||
" \"parameterId\": \"6c3867be-4da5-42c2-93dc-8f509a764003\","
|
||||
" \"parameterType\": \"exceptions\","
|
||||
" \"parameterName\": \"exception\""
|
||||
" }"
|
||||
" ],"
|
||||
" \"zoneId\": \"\","
|
||||
" \"zoneName\": \"\""
|
||||
" }"
|
||||
" ],"
|
||||
" \"exception\": ["
|
||||
" {"
|
||||
" \"context\": \"Any(parameterId(6c3867be-4da5-42c2-93dc-8f509a764003))\","
|
||||
" \"exceptions\": ["
|
||||
" {"
|
||||
" \"match\": {"
|
||||
" \"type\": \"operator\","
|
||||
" \"op\": \"and\","
|
||||
" \"items\": ["
|
||||
" {"
|
||||
" \"type\": \"condition\","
|
||||
" \"op\": \"equals\","
|
||||
" \"key\": \"sourceIdentifier\","
|
||||
" \"value\": [\"1.1.1.1\"]"
|
||||
" }"
|
||||
" ]"
|
||||
" },"
|
||||
" \"behavior\": {"
|
||||
" \"key\": \"log\","
|
||||
" \"value\": \"ignore\""
|
||||
" }"
|
||||
" },"
|
||||
" {"
|
||||
" \"match\": {"
|
||||
" \"type\": \"operator\","
|
||||
" \"op\": \"or\","
|
||||
" \"items\": ["
|
||||
" {"
|
||||
" \"type\": \"condition\","
|
||||
" \"op\": \"equals\","
|
||||
" \"key\": \"protectionName\","
|
||||
" \"value\": [\"Test1\"]"
|
||||
" },"
|
||||
" {"
|
||||
" \"type\": \"condition\","
|
||||
" \"op\": \"equals\","
|
||||
" \"key\": \"protectionName\","
|
||||
" \"value\": [\"Test2\"]"
|
||||
" },"
|
||||
" {"
|
||||
" \"type\": \"condition\","
|
||||
" \"op\": \"equals\","
|
||||
" \"key\": \"sourceIdentifier\","
|
||||
" \"value\": [\"1.1.1.1\"]"
|
||||
" }"
|
||||
" ]"
|
||||
" },"
|
||||
" \"behavior\": {"
|
||||
" \"key\": \"action\","
|
||||
" \"value\": \"accept\""
|
||||
" }"
|
||||
" }"
|
||||
" ]"
|
||||
" }"
|
||||
" ]"
|
||||
" }"
|
||||
"}"
|
||||
);
|
||||
|
||||
istringstream ss(test_config);
|
||||
auto i_config = Singleton::Consume<Config::I_Config>::from(config);
|
||||
i_config->loadConfiguration(ss);
|
||||
|
||||
gen_ctx = make_unique<GenericRulebaseContext>();
|
||||
gen_ctx->activate();
|
||||
}
|
||||
|
||||
void
|
||||
load(const IPSSignaturesResource &policy, const string &severity, const string &confidence)
|
||||
{
|
||||
@@ -261,6 +357,7 @@ public:
|
||||
IPSSignaturesResource performance_signatures3;
|
||||
IPSSignaturesResource single_broken_signature;
|
||||
NiceMock<MockTable> table;
|
||||
NiceMock<MockLogging> logs;
|
||||
MockAgg mock_agg;
|
||||
|
||||
private:
|
||||
@@ -273,7 +370,6 @@ private:
|
||||
ConfigComponent config;
|
||||
Encryptor encryptor;
|
||||
AgentDetails details;
|
||||
StrictMock<MockLogging> logs;
|
||||
IPSEntry ips_state;
|
||||
|
||||
string signature1 =
|
||||
@@ -524,6 +620,23 @@ TEST_F(SignatureTest, basic_load_of_signatures)
|
||||
EXPECT_FALSE(sigs.isEmpty("HTTP_REQUEST_BODY"));
|
||||
}
|
||||
|
||||
TEST_F(SignatureTest, ignore_exception_suppresses_log)
|
||||
{
|
||||
load(single_signature2, "Low or above", "Low");
|
||||
loadExceptionsIgnoreLog();
|
||||
|
||||
expectLog("\"protectionId\": \"Test3\"", "\"eventSeverity\": \"Critical\"");
|
||||
|
||||
EXPECT_TRUE(checkData("gggddd"));
|
||||
|
||||
ScopedContext ctx;
|
||||
ctx.registerValue<string>("sourceIdentifiers", "1.1.1.1");
|
||||
|
||||
// No log should be sent when the exception matches
|
||||
EXPECT_CALL(logs, sendLog(_)).Times(0);
|
||||
EXPECT_FALSE(checkData("gggddd"));
|
||||
}
|
||||
|
||||
TEST_F(SignatureTest, single_signature_matching_override)
|
||||
{
|
||||
load(single_signature, "Low or above", "Low");
|
||||
|
||||
Reference in New Issue
Block a user