mirror of
https://github.com/openappsec/openappsec.git
synced 2025-09-29 19:24:26 +03:00
Feb_06_2024-Dev
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
#add_subdirectory(http_geo_filter)
|
||||
add_subdirectory(http_geo_filter)
|
||||
add_subdirectory(ips)
|
||||
add_subdirectory(layer_7_access_control)
|
||||
add_subdirectory(local_policy_mgmt_gen)
|
||||
|
@@ -69,19 +69,11 @@ checkIDP(shared_ptr<istream> file_stream)
|
||||
#if defined(gaia) || defined(smb)
|
||||
|
||||
Maybe<string>
|
||||
checkIsCpviewRunning(const string &command_output)
|
||||
checkIsInstallHorizonTelemetrySucceeded(const string &command_output)
|
||||
{
|
||||
if (command_output == "true" || command_output == "false") return command_output;
|
||||
if (command_output == "" ) return string("false");
|
||||
|
||||
return genError("cpview is not running");
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
checkIsCPotelcolGRET64(const string &command_output)
|
||||
{
|
||||
if (command_output == "true" || command_output == "false") return command_output;
|
||||
|
||||
return genError("CPotelcol is not installed or its take is below T64");
|
||||
return command_output;
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
@@ -103,6 +95,10 @@ checkCanUpdateSDWanData(const string &command_output)
|
||||
Maybe<string>
|
||||
getMgmtObjType(const string &command_output)
|
||||
{
|
||||
if (getenv("WAAP_DIR")) {
|
||||
return string("CloudGuard WAF Gateway");
|
||||
}
|
||||
|
||||
if (!command_output.empty()) {
|
||||
if (command_output[0] == '1') return string("management");
|
||||
if (command_output[0] == '0') return string("gateway");
|
||||
|
@@ -39,14 +39,10 @@ SHELL_PRE_CMD("read sdwan data",
|
||||
#ifdef SHELL_CMD_HANDLER
|
||||
#if defined(gaia) || defined(smb)
|
||||
SHELL_CMD_HANDLER("cpProductIntegrationMgmtObjectType", "cpprod_util CPPROD_IsMgmtMachine", getMgmtObjType)
|
||||
SHELL_CMD_HANDLER("isCpviewRunning",
|
||||
"pidof cpview_api_service > /dev/null 2>&1 && [ -f $CPDIR/conf/cpview_api_service.version ] "
|
||||
"&& echo 'true' || echo 'false'",
|
||||
checkIsCpviewRunning)
|
||||
SHELL_CMD_HANDLER("isCPotelcolGRET64",
|
||||
"grep -A 10 '(BUNDLE_CPOTELCOL_AUTOUPDATE' ${CPDIR}/registry/HKLM_registry.data | "
|
||||
"awk '/SU_Build_Take/{val = substr($2, 2, length($2)-2); if (val >=64) print \"true\"; else print \"false\" }'",
|
||||
checkIsCPotelcolGRET64)
|
||||
SHELL_CMD_HANDLER("prerequisitesForHorizonTelemetry",
|
||||
"[ -f /var/log/nano_agent/cp-nano-horizon-telemetry-prerequisites.log ] "
|
||||
"&& head -1 /var/log/nano_agent/cp-nano-horizon-telemetry-prerequisites.log || echo ''",
|
||||
checkIsInstallHorizonTelemetrySucceeded)
|
||||
SHELL_CMD_HANDLER("hasSDWan", "[ -f $FWDIR/bin/sdwan_steering ] && echo '1' || echo '0'", checkHasSDWan)
|
||||
SHELL_CMD_HANDLER(
|
||||
"canUpdateSDWanData",
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "reverse_proxy_defaults.h"
|
||||
#include "config.h"
|
||||
#include "log_generator.h"
|
||||
#include "health_check_manager.h"
|
||||
@@ -28,6 +29,8 @@ using namespace ReportIS;
|
||||
|
||||
USE_DEBUG_FLAG(D_HEALTH_CHECK);
|
||||
|
||||
static const std::string all_services_running = "/tmp/wd.all_running";
|
||||
|
||||
class HealthChecker::Impl
|
||||
{
|
||||
public:
|
||||
@@ -36,6 +39,7 @@ public:
|
||||
{
|
||||
i_mainloop = Singleton::Consume<I_MainLoop>::by<HealthChecker>();
|
||||
i_socket = Singleton::Consume<I_Socket>::by<HealthChecker>();
|
||||
i_orchestration_status = Singleton::Consume<I_OrchestrationStatus>::by<HealthChecker>();
|
||||
initConfig();
|
||||
initServerSocket();
|
||||
|
||||
@@ -255,35 +259,33 @@ private:
|
||||
{
|
||||
if (!getenv("DOCKER_RPM_ENABLED")) return HealthCheckStatus::IGNORED;
|
||||
|
||||
static const string standalone_cmd = "/usr/sbin/cpnano -s --docker-rpm; echo $?";
|
||||
static int timeout_tolerance = 1;
|
||||
static HealthCheckStatus health_status = HealthCheckStatus::HEALTHY;
|
||||
|
||||
dbgTrace(D_HEALTH_CHECK) << "Checking the standalone docker health status with command: " << standalone_cmd;
|
||||
|
||||
auto maybe_result = Singleton::Consume<I_ShellCmd>::by<HealthChecker>()->getExecOutput(standalone_cmd, 5000);
|
||||
if (!maybe_result.ok()) {
|
||||
if (maybe_result.getErr().find("Reached timeout") != string::npos) {
|
||||
dbgWarning(D_HEALTH_CHECK)
|
||||
<< "Reached timeout while querying standalone health status, attempt number: "
|
||||
<< timeout_tolerance;
|
||||
|
||||
return health_status == HealthCheckStatus::UNHEALTHY || timeout_tolerance++ > 3 ?
|
||||
HealthCheckStatus::UNHEALTHY :
|
||||
health_status;
|
||||
}
|
||||
|
||||
dbgWarning(D_HEALTH_CHECK) << "Unable to get the standalone docker status. Returning unhealthy status.";
|
||||
if (i_orchestration_status->getPolicyVersion().empty()) {
|
||||
dbgTrace(D_HEALTH_CHECK) << "Policy version is empty, returning unhealthy status";
|
||||
return HealthCheckStatus::UNHEALTHY;
|
||||
}
|
||||
dbgTrace(D_HEALTH_CHECK) << "Got response: " << maybe_result.unpack();
|
||||
|
||||
auto response = NGEN::Strings::removeTrailingWhitespaces(maybe_result.unpack());
|
||||
if (!NGEN::Filesystem::exists(all_services_running)) {
|
||||
dbgTrace(D_HEALTH_CHECK) << all_services_running << " does not exist, returning unhealthy status";
|
||||
return HealthCheckStatus::UNHEALTHY;
|
||||
}
|
||||
|
||||
if (response.back() == '1') return health_status = HealthCheckStatus::UNHEALTHY;
|
||||
if (NGEN::Filesystem::exists(rpm_full_load_path)) {
|
||||
dbgTrace(D_HEALTH_CHECK) << rpm_full_load_path << " exists, returning healthy status";
|
||||
return HealthCheckStatus::HEALTHY;
|
||||
}
|
||||
|
||||
timeout_tolerance = 1;
|
||||
return health_status = (response.back() == '0') ? HealthCheckStatus::HEALTHY : HealthCheckStatus::DEGRADED;
|
||||
if (NGEN::Filesystem::exists(rpm_partial_load_path)) {
|
||||
dbgTrace(D_HEALTH_CHECK) << rpm_partial_load_path << " exists, returning degraded status";
|
||||
return HealthCheckStatus::DEGRADED;
|
||||
}
|
||||
|
||||
if (!NGEN::Filesystem::exists(first_rpm_policy_load_path)) {
|
||||
dbgTrace(D_HEALTH_CHECK) << "Could not load latest RPM policy, returning degraded status";
|
||||
return HealthCheckStatus::DEGRADED;
|
||||
}
|
||||
|
||||
dbgTrace(D_HEALTH_CHECK) << "RPM is not loaded, returning unhealthy status";
|
||||
return HealthCheckStatus::UNHEALTHY;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -390,7 +392,7 @@ private:
|
||||
|
||||
if (standalone_status == HealthCheckStatus::UNHEALTHY) {
|
||||
dbgDebug(D_HEALTH_CHECK)
|
||||
<< "Standalone status in unhealthy, returning the following response: "
|
||||
<< "Standalone status is unhealthy, returning the following response: "
|
||||
<< failure_response;
|
||||
i_socket->writeData(curr_client_socket, failure_response_buffer);
|
||||
closeCurrentSocket(curr_client_socket, curr_routine_id);
|
||||
@@ -439,6 +441,7 @@ private:
|
||||
I_MainLoop *i_mainloop = nullptr;
|
||||
I_Socket *i_socket = nullptr;
|
||||
I_Health_Check_Manager *i_health_check_manager = nullptr;
|
||||
I_OrchestrationStatus *i_orchestration_status = nullptr;
|
||||
};
|
||||
|
||||
HealthChecker::HealthChecker() : Component("HealthChecker"), pimpl(make_unique<Impl>()) {}
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#include "mock/mock_socket_is.h"
|
||||
#include "mock/mock_mainloop.h"
|
||||
#include "mock/mock_shell_cmd.h"
|
||||
#include "mock/mock_orchestration_status.h"
|
||||
#include "health_check_manager.h"
|
||||
|
||||
#include "config.h"
|
||||
@@ -65,6 +66,7 @@ public:
|
||||
AgentDetails agent_details;
|
||||
StrictMock<MockSocketIS> mock_socket;
|
||||
NiceMock<MockShellCmd> mock_shell_cmd;
|
||||
NiceMock<MockOrchestrationStatus> mock_orchestration_status;
|
||||
I_Socket::socketFd server_socket = -1;
|
||||
Context ctx;
|
||||
ConfigComponent config;
|
||||
@@ -72,7 +74,6 @@ public:
|
||||
I_MainLoop::Routine connection_handler_routine;
|
||||
I_MainLoop::Routine client_connection_handler_routine;
|
||||
I_MainLoop::Routine handle_probe_routine;
|
||||
//StrictMock<MockHealthCheckManager> mock_health_check_manager;
|
||||
HealthCheckManager health_check_manager;
|
||||
I_Health_Check_Manager *i_health_check_manager;
|
||||
};
|
||||
|
@@ -102,6 +102,7 @@ public:
|
||||
|
||||
Maybe<void> authenticateAgent() override;
|
||||
void setAddressExtenesion(const std::string &extension) override;
|
||||
static std::string getUserEdition();
|
||||
|
||||
protected:
|
||||
class UserCredentials
|
||||
@@ -142,7 +143,6 @@ protected:
|
||||
std::string base64Encode(const std::string &in) const;
|
||||
std::string buildBasicAuthHeader(const std::string &username, const std::string &pass) const;
|
||||
std::string buildOAuth2Header(const std::string &token) const;
|
||||
std::string getUserEdition() const;
|
||||
|
||||
// This apps which the orchestrations requires them from Fog.
|
||||
std::vector<std::string> required_security_apps;
|
||||
|
@@ -56,7 +56,9 @@ public:
|
||||
|
||||
private:
|
||||
Maybe<std::string> getNewVersion();
|
||||
void doLocalFogOperations(const std::string &policy) const;
|
||||
|
||||
std::string tuning_host;
|
||||
I_DeclarativePolicy *i_declarative_policy = nullptr;
|
||||
};
|
||||
|
||||
|
@@ -41,6 +41,7 @@
|
||||
#include "env_details.h"
|
||||
#include "hybrid_communication.h"
|
||||
#include "agent_core_utilities.h"
|
||||
#include "fog_communication.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace chrono;
|
||||
@@ -190,7 +191,8 @@ public:
|
||||
);
|
||||
|
||||
auto orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<OrchestrationComp>();
|
||||
orchestration_tools->getClusterId();
|
||||
|
||||
if (getAttribute("no-setting", "IGNORE_CLUSTER_ID") != "TRUE") orchestration_tools->getClusterId();
|
||||
|
||||
hybrid_mode_metric.init(
|
||||
"Watchdog Metrics",
|
||||
@@ -1484,6 +1486,8 @@ private:
|
||||
agent_data_report << AgentReportFieldWithLabel("managedMode", "management");
|
||||
}
|
||||
|
||||
agent_data_report << AgentReportFieldWithLabel("userEdition", FogCommunication::getUserEdition());
|
||||
|
||||
#if defined(gaia) || defined(smb)
|
||||
if (i_details_resolver->compareCheckpointVersion(8100, greater_equal<int>())) {
|
||||
agent_data_report << AgentReportFieldWithLabel("isCheckpointVersionGER81", "true");
|
||||
|
@@ -3,7 +3,7 @@
|
||||
#include <string>
|
||||
|
||||
std::string
|
||||
FogAuthenticator::getUserEdition() const
|
||||
FogAuthenticator::getUserEdition()
|
||||
{
|
||||
return "community";
|
||||
}
|
||||
|
@@ -27,15 +27,19 @@ using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_ORCHESTRATOR);
|
||||
|
||||
#define TUNING_HOST_ENV_NAME "TUNING_HOST"
|
||||
static const string defaultTuningHost = "appsec-tuning-svc";
|
||||
static const string agent_resource_api = "/api/v2/agents/resources";
|
||||
|
||||
void
|
||||
HybridCommunication::init()
|
||||
{
|
||||
dbgTrace(D_ORCHESTRATOR) << "Initializing the Hybrid Communication Component";
|
||||
|
||||
FogAuthenticator::init();
|
||||
i_declarative_policy = Singleton::Consume<I_DeclarativePolicy>::from<DeclarativePolicyUtils>();
|
||||
dbgTrace(D_ORCHESTRATOR) << "Initializing the Hybrid Communication Component";
|
||||
|
||||
auto env_tuning_host = getenv("TUNING_HOST");
|
||||
tuning_host = env_tuning_host != nullptr ? env_tuning_host : "appsec-tuning-svc";
|
||||
|
||||
if (getConfigurationFlag("otp") != "") {
|
||||
otp = getConfigurationFlag("otp");
|
||||
} else {
|
||||
@@ -49,10 +53,9 @@ HybridCommunication::getUpdate(CheckUpdateRequest &request)
|
||||
string manifest_checksum = "";
|
||||
dbgTrace(D_ORCHESTRATOR) << "Getting updates in Hybrid Communication";
|
||||
if (access_token.ok()) {
|
||||
static const string check_update_str = "/api/v2/agents/resources";
|
||||
auto request_status = Singleton::Consume<I_Messaging>::by<HybridCommunication>()->sendSyncMessage(
|
||||
HTTPMethod::POST,
|
||||
check_update_str,
|
||||
agent_resource_api,
|
||||
request
|
||||
);
|
||||
|
||||
@@ -78,45 +81,7 @@ HybridCommunication::getUpdate(CheckUpdateRequest &request)
|
||||
|
||||
string policy_response = i_declarative_policy->getUpdate(request);
|
||||
|
||||
auto env = Singleton::Consume<I_EnvDetails>::by<HybridCommunication>()->getEnvType();
|
||||
if (env == EnvType::K8S && !policy_response.empty()) {
|
||||
dbgDebug(D_ORCHESTRATOR) << "Policy has changes, sending notification to tuning host";
|
||||
I_AgentDetails *agentDetails = Singleton::Consume<I_AgentDetails>::by<HybridCommunication>();
|
||||
|
||||
auto get_tuning_host = []()
|
||||
{
|
||||
static string tuning_host;
|
||||
if (tuning_host != "") return tuning_host;
|
||||
|
||||
char* tuning_host_env = getenv(TUNING_HOST_ENV_NAME);
|
||||
if (tuning_host_env != NULL) {
|
||||
tuning_host = string(tuning_host_env);
|
||||
return tuning_host;
|
||||
}
|
||||
dbgWarning(D_ORCHESTRATOR) << "tuning host is not set. using default";
|
||||
tuning_host = defaultTuningHost;
|
||||
|
||||
return tuning_host;
|
||||
};
|
||||
|
||||
MessageMetadata update_policy_crd_md(get_tuning_host(), 80);
|
||||
update_policy_crd_md.insertHeader("X-Tenant-Id", agentDetails->getTenantId());
|
||||
UpdatePolicyCrdObject policy_change_object(policy_response);
|
||||
|
||||
auto i_messaging = Singleton::Consume<I_Messaging>::by<HybridCommunication>();
|
||||
bool tuning_req_status = i_messaging->sendSyncMessageWithoutResponse(
|
||||
HTTPMethod::POST,
|
||||
"/api/update-policy-crd",
|
||||
policy_change_object,
|
||||
MessageCategory::GENERIC,
|
||||
update_policy_crd_md
|
||||
);
|
||||
if (!tuning_req_status) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to send tuning notification";
|
||||
} else {
|
||||
dbgDebug(D_ORCHESTRATOR) << "Successfully sent tuning policy update notification";
|
||||
}
|
||||
}
|
||||
doLocalFogOperations(policy_response);
|
||||
|
||||
request = CheckUpdateRequest(manifest_checksum, policy_response, "", "", "", "");
|
||||
|
||||
@@ -141,10 +106,9 @@ HybridCommunication::downloadAttributeFile(const GetResourceFile &resourse_file,
|
||||
|
||||
auto unpacked_access_token = access_token.unpack().getToken();
|
||||
|
||||
static const string file_attribute_str = "/api/v2/agents/resources/";
|
||||
auto attribute_file = Singleton::Consume<I_Messaging>::by<HybridCommunication>()->downloadFile(
|
||||
resourse_file.getRequestMethod(),
|
||||
file_attribute_str + resourse_file.getFileName(),
|
||||
agent_resource_api + '/' + resourse_file.getFileName(),
|
||||
file_path
|
||||
);
|
||||
if (!attribute_file.ok()) {
|
||||
@@ -164,3 +128,33 @@ HybridCommunication::sendPolicyVersion(const string &policy_version, const strin
|
||||
policy_version.empty();
|
||||
return Maybe<void>();
|
||||
}
|
||||
|
||||
void
|
||||
HybridCommunication::doLocalFogOperations(const string &policy) const
|
||||
{
|
||||
if (policy.empty()) return;
|
||||
if (Singleton::Consume<I_EnvDetails>::by<HybridCommunication>()->getEnvType() != EnvType::K8S) return;
|
||||
|
||||
dbgDebug(D_ORCHESTRATOR) << "Policy has changes, sending notification to tuning host";
|
||||
|
||||
MessageMetadata update_policy_crd_md(tuning_host, 80);
|
||||
const auto &tenant_id = Singleton::Consume<I_AgentDetails>::by<HybridCommunication>()->getTenantId();
|
||||
update_policy_crd_md.insertHeader("X-Tenant-Id", tenant_id);
|
||||
|
||||
UpdatePolicyCrdObject policy_change_object(policy);
|
||||
auto i_messaging = Singleton::Consume<I_Messaging>::by<HybridCommunication>();
|
||||
bool tuning_req_status = i_messaging->sendSyncMessageWithoutResponse(
|
||||
HTTPMethod::POST,
|
||||
"/api/update-policy-crd",
|
||||
policy_change_object,
|
||||
MessageCategory::GENERIC,
|
||||
update_policy_crd_md
|
||||
);
|
||||
|
||||
if (!tuning_req_status) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to send tuning notification";
|
||||
} else {
|
||||
dbgDebug(D_ORCHESTRATOR) << "Successfully sent tuning policy update notification";
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -85,6 +85,7 @@ add_library(waap_clib
|
||||
ParserGql.cc
|
||||
ParserPercentEncode.cc
|
||||
ParserPairs.cc
|
||||
Waf2Util2.cc
|
||||
)
|
||||
|
||||
add_definitions("-Wno-unused-function")
|
||||
|
@@ -864,10 +864,6 @@ DeepParser::parseAfterMisleadingMultipartBoundaryCleaned(
|
||||
return rc;
|
||||
}
|
||||
|
||||
static bool err = false;
|
||||
static const SingleRegex json_detector_re("\\A[{\\[][^;\",}\\]]*[,:\"].+[\\s\\S]", err, "json_detector");
|
||||
static const SingleRegex json_quoteless_detector_re("^[{\\[][[,0-9nul\\]]+", err, "json_quoteless_detector");
|
||||
|
||||
//intended to keep and process all types of leftovers detected as separate cases for parsing
|
||||
int
|
||||
DeepParser::createUrlParserForJson(
|
||||
@@ -1103,11 +1099,7 @@ DeepParser::createInternalParser(
|
||||
} else {
|
||||
dbgTrace(D_WAAP_DEEP_PARSER) << "attempt to find JSON by '{' or '['";
|
||||
bool percent_encoded_doublequote_detected = cur_val.find("%22") != std::string::npos;
|
||||
if (json_detector_re.hasMatch(cur_val)
|
||||
&& (valueStats.hasDoubleQuote
|
||||
|| json_quoteless_detector_re.hasMatch(cur_val)
|
||||
|| percent_encoded_doublequote_detected)) {
|
||||
// JSON value detected
|
||||
if (Waap::Util::isValidJson(cur_val)) {
|
||||
if (percent_encoded_doublequote_detected && !valueStats.hasDoubleQuote) {
|
||||
// We have JSOn but it %-encoded, first start percent decoding for it. Very narrow case
|
||||
dbgTrace(D_WAAP_DEEP_PARSER) << "Starting to parse a JSON file from percent decoding";
|
||||
|
@@ -19,7 +19,8 @@ USE_DEBUG_FLAG(D_WAAP_PARSER);
|
||||
|
||||
// Max size for key and value that can be stored in memory (per thread)
|
||||
#define MAX_KEY_SIZE 64*1024
|
||||
#define MAX_VALUE_SIZE 64*1024
|
||||
#define MAX_VALUE_SIZE 16*1024
|
||||
#define MAX_PROCESSING_BUFFER_SIZE 64*1024
|
||||
|
||||
BufferedReceiver::BufferedReceiver(IParserReceiver &receiver, size_t parser_depth) :
|
||||
m_receiver(receiver),
|
||||
@@ -69,14 +70,14 @@ int BufferedReceiver::onValue(const char *v, size_t v_len)
|
||||
<< m_parser_depth;
|
||||
while (v_len > 0) {
|
||||
// Move data from buffer v to accumulated m_value string in an attempt to fill m_value to its max size
|
||||
size_t bytesToFill = std::min(v_len, MAX_VALUE_SIZE - m_value.size());
|
||||
size_t bytesToFill = std::min(v_len, MAX_PROCESSING_BUFFER_SIZE - m_value.size());
|
||||
m_value += std::string(v, bytesToFill);
|
||||
// Update v and v_len (input buffer) to reflect that we already consumed part (or all) of it
|
||||
v += bytesToFill;
|
||||
v_len -= bytesToFill;
|
||||
|
||||
// Only push full buffers to the m_receiver
|
||||
if (m_value.size() == MAX_VALUE_SIZE) {
|
||||
if (m_value.size() >= MAX_VALUE_SIZE) {
|
||||
// The first full-size buffer will be pushed with BUFFERED_RECEIVER_F_FIRST flag
|
||||
dbgTrace(D_WAAP_PARSER)
|
||||
<< " The first full-size buffer will be pushed with BUFFERED_RECEIVER_F_FIRST flag"
|
||||
|
@@ -22,8 +22,9 @@
|
||||
#include "yajl/yajl_parse.h"
|
||||
#include "singleton.h"
|
||||
#include "i_oa_schema_updater.h"
|
||||
|
||||
#define FIRST_JSON_BUFFER_SIZE 4 // must buffer at least 4 first bytes to allow unicode autodetection (BOM).
|
||||
// must be at least 4 first bytes to allow unicode autodetection (BOM).
|
||||
// BUT... reduced to 1 in order to allow better work of schema validation and API discovery
|
||||
#define FIRST_JSON_BUFFER_SIZE 1
|
||||
|
||||
typedef size_t yajl_size_t;
|
||||
|
||||
|
@@ -312,6 +312,7 @@ Waf2Transaction::Waf2Transaction() :
|
||||
m_responseInjectReasons(),
|
||||
m_index(-1),
|
||||
m_triggerLog(),
|
||||
is_schema_validation(false),
|
||||
m_waf2TransactionFlags()
|
||||
{}
|
||||
|
||||
@@ -343,6 +344,7 @@ Waf2Transaction::Waf2Transaction(std::shared_ptr<WaapAssetState> pWaapAssetState
|
||||
m_responseInjectReasons(),
|
||||
m_index(-1),
|
||||
m_triggerLog(),
|
||||
is_schema_validation(false),
|
||||
m_waf2TransactionFlags()
|
||||
{}
|
||||
|
||||
@@ -515,7 +517,6 @@ bool Waf2Transaction::checkIsScanningRequired()
|
||||
m_siteConfig = &m_ngenAPIConfig;
|
||||
auto rateLimitingPolicy = m_siteConfig ? m_siteConfig->get_RateLimitingPolicy() : NULL;
|
||||
result |= m_siteConfig->get_WebAttackMitigation();
|
||||
|
||||
if(rateLimitingPolicy) {
|
||||
result |= m_siteConfig->get_RateLimitingPolicy()->getRateLimitingEnforcementStatus();
|
||||
}
|
||||
|
@@ -345,6 +345,7 @@ private:
|
||||
|
||||
// Cached pointer to const triggerLog (hence mutable)
|
||||
mutable std::shared_ptr<Waap::Trigger::Log> m_triggerLog;
|
||||
bool is_schema_validation = false;
|
||||
Waf2TransactionFlags m_waf2TransactionFlags;
|
||||
};
|
||||
|
||||
|
@@ -2055,31 +2055,18 @@ string extractForwardedIp(const string &x_forwarded_hdr_val)
|
||||
return forward_ip;
|
||||
}
|
||||
|
||||
|
||||
bool isUuid(const string& str) {
|
||||
if (str.length() != 36) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool err;
|
||||
static const SingleRegex uuid_detector_re(
|
||||
"[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}",
|
||||
err,
|
||||
"uuid_detector"
|
||||
);
|
||||
// Check if the string matches the UUID format
|
||||
// Check if the string matches the UUID format
|
||||
return uuid_detector_re.hasMatch(str);
|
||||
/*
|
||||
boost::cmatch what;
|
||||
try {
|
||||
static const boost::regex uuidRegex("[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}");
|
||||
// Check if the string matches the UUID format
|
||||
return boost::regex_match(str.c_str(), what, uuidRegex);
|
||||
} catch (std::runtime_error &e) {
|
||||
dbgError(D_WAAP) << e.what();
|
||||
}
|
||||
return false;
|
||||
*/
|
||||
}
|
||||
|
||||
bool isIpAddress(const string &ip_address)
|
||||
|
@@ -876,6 +876,8 @@ namespace Util {
|
||||
std::string::const_iterator e,
|
||||
std::string &repl);
|
||||
|
||||
bool isValidJson(const std::string &input);
|
||||
|
||||
bool detectJSONasParameter(const std::string &s,
|
||||
std::string &key,
|
||||
std::string &value);
|
||||
|
632
components/security_apps/waap/waap_clib/Waf2Util2.cc
Normal file
632
components/security_apps/waap/waap_clib/Waf2Util2.cc
Normal file
@@ -0,0 +1,632 @@
|
||||
#include "Waf2Util.h"
|
||||
#include <string>
|
||||
|
||||
namespace Waap {
|
||||
namespace Util {
|
||||
using namespace std;
|
||||
|
||||
static const char *trueString = "true";
|
||||
static const size_t trueStringLen = strlen(trueString);
|
||||
static const char *falseString = "false";
|
||||
static const size_t falseStringLen = strlen(falseString);
|
||||
static const char *nullString = "null";
|
||||
static const size_t nullStringLen = strlen(nullString);
|
||||
static const char *quoteString = "%22";
|
||||
static const size_t quoteStringLen = strlen(quoteString);
|
||||
|
||||
int
|
||||
isAlignedPrefix(
|
||||
const char *sample,
|
||||
const size_t sample_len,
|
||||
const char *buffer,
|
||||
const size_t buffer_len)
|
||||
{
|
||||
size_t lookup_len = 0;
|
||||
if (buffer_len < sample_len) {
|
||||
lookup_len = buffer_len;
|
||||
} else {
|
||||
lookup_len = sample_len;
|
||||
}
|
||||
if (strncmp(sample, buffer, lookup_len) == 0) {
|
||||
return lookup_len;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
isBoolean(
|
||||
const char *buffer,
|
||||
const size_t buffer_len)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = isAlignedPrefix(trueString, trueStringLen, buffer, buffer_len);
|
||||
if (status >= 0) {
|
||||
return status;
|
||||
}
|
||||
status = isAlignedPrefix(falseString, falseStringLen, buffer, buffer_len);
|
||||
if (status >= 0) {
|
||||
return status;
|
||||
}
|
||||
status = isAlignedPrefix(nullString, nullStringLen, buffer, buffer_len);
|
||||
if (status >= 0) {
|
||||
return status;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool
|
||||
isValidExponent(
|
||||
const char * buffer,
|
||||
const size_t buffer_len,
|
||||
size_t *i)
|
||||
{
|
||||
if (buffer_len == *i + 1) {
|
||||
return true; // e or E is the last char in buffer
|
||||
}
|
||||
if (*i + 1 < buffer_len && (isdigit(buffer[*i + 1]) || (buffer[*i + 1] == '+' || buffer[*i + 1] == '-'))) {
|
||||
(*i) += 1;
|
||||
if (isdigit(buffer[*i + 1])) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
isObjectStart(const char c, int *object_count)
|
||||
{
|
||||
if (c == '{') {
|
||||
(*object_count)++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
isObjectEnd(const char c, int *object_count)
|
||||
{
|
||||
if (c == '}') {
|
||||
(*object_count)--;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
isArrayStart(const char c, int *array_count)
|
||||
{
|
||||
if (c == '[') {
|
||||
(*array_count)++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
isArrayEnd(const char c, int *array_count)
|
||||
{
|
||||
if (c == ']') {
|
||||
(*array_count)--;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
isValidJson(const std::string &input)
|
||||
{
|
||||
static const size_t MAX_JSON_INSPECT_SIZE = 16;
|
||||
|
||||
enum state
|
||||
{
|
||||
S_START, // 0
|
||||
S_OBJECT_START, // 1
|
||||
S_OBJECT_END, // 2
|
||||
S_ARRAY_START, // 3
|
||||
S_ARRAY_END, // 4
|
||||
S_NUMBER, // 5
|
||||
S_NUMBER_END, // 6
|
||||
S_STRING_START, // 7
|
||||
S_STRING_BODY, // 8
|
||||
S_STRING_END, // 9
|
||||
S_VARIABLE_START, // 10
|
||||
S_VARIABLE_BODY, // 11
|
||||
S_VARIABLE_END, // 12
|
||||
S_COMMA, // 13
|
||||
S_COLON, // 14
|
||||
S_BOOLEAN, // 15
|
||||
S_ERROR, // 16
|
||||
S_END // 17
|
||||
};
|
||||
|
||||
state m_state;
|
||||
bool encoded = false;
|
||||
size_t i = 0;
|
||||
char c;
|
||||
const char *buf = input.c_str();
|
||||
size_t len = input.length();
|
||||
int array_count = 0;
|
||||
int object_count = 0;
|
||||
int status;
|
||||
if (len < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_state = S_START;
|
||||
while (i < len && i < MAX_JSON_INSPECT_SIZE) {
|
||||
c = buf[i];
|
||||
if (c == 0x0) { // UTF16 to UTF8 support
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
switch (m_state) {
|
||||
case S_START:
|
||||
if (isObjectStart(c, &object_count)) {
|
||||
m_state = S_OBJECT_START;
|
||||
break;
|
||||
}
|
||||
if (isArrayStart(c, &array_count)) {
|
||||
m_state = S_ARRAY_START;
|
||||
break;
|
||||
}
|
||||
m_state = S_ERROR;
|
||||
break; // S_START
|
||||
|
||||
case S_OBJECT_START:
|
||||
if (isObjectEnd(c, &object_count)) {
|
||||
m_state = S_OBJECT_END;
|
||||
break;
|
||||
}
|
||||
if (c == '\"') {
|
||||
m_state = S_VARIABLE_START;
|
||||
break;
|
||||
}
|
||||
if (isspace(c)) {
|
||||
break;
|
||||
}
|
||||
status = isAlignedPrefix(quoteString, quoteStringLen, buf + i, len - i);
|
||||
if (status >= 0) {
|
||||
m_state = S_VARIABLE_START;
|
||||
encoded = true;
|
||||
i += status - 1;
|
||||
break;
|
||||
}
|
||||
m_state = S_ERROR;
|
||||
break; // object_start
|
||||
|
||||
case S_ARRAY_START:
|
||||
if (isObjectStart(c, &object_count)) {
|
||||
m_state = S_OBJECT_START;
|
||||
break;
|
||||
}
|
||||
if (isArrayStart(c, &array_count)) {
|
||||
// keep state unchanged
|
||||
break;
|
||||
}
|
||||
if (isArrayEnd(c, &array_count)) {
|
||||
m_state = S_ARRAY_END;
|
||||
break;
|
||||
}
|
||||
if (isdigit(c)) {
|
||||
m_state = S_NUMBER;
|
||||
break;
|
||||
}
|
||||
if (c == '-') {
|
||||
if (i + 1 == len) { // End of buffer case
|
||||
m_state = S_NUMBER;
|
||||
break;
|
||||
}
|
||||
if (i + 1 < len && isdigit(buf[i + 1])) {
|
||||
m_state = S_NUMBER;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
m_state = S_ERROR;
|
||||
break;
|
||||
}
|
||||
if (isspace(c)) {
|
||||
break;
|
||||
}
|
||||
if (c == '\"') {
|
||||
m_state = S_STRING_START;
|
||||
break;
|
||||
}
|
||||
status = isAlignedPrefix(quoteString, quoteStringLen, buf + i, len - i);
|
||||
if (status >= 0) {
|
||||
m_state = S_STRING_START;
|
||||
encoded = true;
|
||||
i += status - 1;
|
||||
break;
|
||||
} else {
|
||||
m_state = S_ERROR;
|
||||
}
|
||||
status = isBoolean(buf + i, len - i);
|
||||
if (status >= 0) {
|
||||
m_state = S_BOOLEAN;
|
||||
i += status - 1;
|
||||
break;
|
||||
}
|
||||
m_state = S_ERROR;
|
||||
break; // array_start
|
||||
|
||||
case S_OBJECT_END:
|
||||
if (isspace(c)) {
|
||||
break;
|
||||
}
|
||||
if (c == ',') {
|
||||
m_state = S_COMMA;
|
||||
break;
|
||||
}
|
||||
if (isArrayEnd(c, &array_count)) {
|
||||
m_state = S_ARRAY_END;
|
||||
break;
|
||||
}
|
||||
if (isObjectEnd(c, &object_count)) {
|
||||
m_state = S_OBJECT_END;
|
||||
break;
|
||||
}
|
||||
if (isArrayStart(c, &array_count)) { // nJSON support but contradicts to definition of json.org
|
||||
m_state = S_ARRAY_START;
|
||||
break;
|
||||
}
|
||||
if (isObjectStart(c, &object_count)) { // nJSON support but contradicts to definition of json.org
|
||||
m_state = S_OBJECT_START;
|
||||
break;
|
||||
}
|
||||
m_state = S_ERROR;
|
||||
break; // S_OBJECT_END
|
||||
|
||||
case S_ARRAY_END:
|
||||
if (isspace(c)) {
|
||||
break;
|
||||
}
|
||||
if (c == ',') {
|
||||
m_state = S_COMMA;
|
||||
break;
|
||||
}
|
||||
if (isArrayEnd(c, &array_count)) {
|
||||
m_state = S_ARRAY_END;
|
||||
break;
|
||||
}
|
||||
if (isObjectEnd(c, &object_count)) {
|
||||
m_state = S_OBJECT_END;
|
||||
break;
|
||||
}
|
||||
if (isArrayStart(c, &array_count)) { // nJSON support but contradicts to definition of json.org
|
||||
m_state = S_ARRAY_START;
|
||||
break;
|
||||
}
|
||||
if (isObjectStart(c, &object_count)) { // nJSON support but contradicts to definition of json.org
|
||||
m_state = S_OBJECT_START;
|
||||
break;
|
||||
}
|
||||
m_state = S_ERROR;
|
||||
break; // S_ARRAY_END
|
||||
|
||||
case S_NUMBER:
|
||||
if (isdigit(c)) {
|
||||
break;
|
||||
}
|
||||
if (c == '.') {
|
||||
if (i + 1 == len) { // End of buffer case
|
||||
m_state = S_NUMBER;
|
||||
break;
|
||||
}
|
||||
if (i + 1 < len && isdigit(buf[i + 1])) {
|
||||
m_state = S_NUMBER;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
m_state = S_ERROR;
|
||||
break;
|
||||
}
|
||||
if (c == 'e' || c == 'E') {
|
||||
if (isValidExponent(buf, len, &i)) {
|
||||
m_state = S_NUMBER;
|
||||
break;
|
||||
}
|
||||
m_state = S_ERROR;
|
||||
break;
|
||||
}
|
||||
if (isspace(c)) {
|
||||
m_state = S_NUMBER_END;
|
||||
break;
|
||||
}
|
||||
if (c == ',') {
|
||||
m_state = S_COMMA;
|
||||
break;
|
||||
}
|
||||
if (isArrayEnd(c, &array_count)) {
|
||||
m_state = S_ARRAY_END;
|
||||
break;
|
||||
}
|
||||
if (isObjectEnd(c, &object_count)) {
|
||||
m_state = S_OBJECT_END;
|
||||
break;
|
||||
}
|
||||
m_state = S_ERROR;
|
||||
break; // S_NUMBER
|
||||
|
||||
case S_NUMBER_END:
|
||||
if (isspace(c)) {
|
||||
break;
|
||||
}
|
||||
if (c == ',') {
|
||||
m_state = S_COMMA;
|
||||
break;
|
||||
}
|
||||
if (isArrayEnd(c, &array_count)) {
|
||||
m_state = S_ARRAY_END;
|
||||
break;
|
||||
}
|
||||
if (isObjectEnd(c, &object_count)) {
|
||||
m_state = S_OBJECT_END;
|
||||
break;
|
||||
}
|
||||
m_state = S_ERROR;
|
||||
break; // S_NUMBER_END
|
||||
|
||||
case S_STRING_START:
|
||||
if (c == '\"') {
|
||||
m_state = S_STRING_END;
|
||||
break;
|
||||
}
|
||||
if (encoded) { // url_encoded quote
|
||||
status = isAlignedPrefix(quoteString, quoteStringLen, buf + i, len - i);
|
||||
if (status >= 0) {
|
||||
m_state = S_STRING_END;
|
||||
encoded = true;
|
||||
i += status - 1;
|
||||
break;
|
||||
} else {
|
||||
m_state = S_ERROR;
|
||||
}
|
||||
}
|
||||
m_state = S_STRING_BODY;
|
||||
break; // S_STRING_START
|
||||
|
||||
case S_STRING_BODY:
|
||||
if (c == '\"') {
|
||||
if (buf[i - 1] == '\\' && buf[i - 2] != '\\') {
|
||||
m_state = S_STRING_BODY;
|
||||
break;
|
||||
} else {
|
||||
m_state = S_STRING_END;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (encoded) { // url_encoded quote
|
||||
status = isAlignedPrefix(quoteString, quoteStringLen, buf + i, len - i);
|
||||
if (status >= 0) {
|
||||
m_state = S_STRING_END;
|
||||
encoded = true;
|
||||
i += status - 1;
|
||||
break;
|
||||
} else {
|
||||
m_state = S_ERROR;
|
||||
}
|
||||
}
|
||||
m_state = S_STRING_BODY;
|
||||
break; // S_STRING_BODY;
|
||||
|
||||
case S_STRING_END:
|
||||
if (isspace(c)) {
|
||||
break;
|
||||
}
|
||||
if (c == ',') {
|
||||
m_state = S_COMMA;
|
||||
break;
|
||||
}
|
||||
if (isArrayEnd(c, &array_count)) {
|
||||
m_state = S_ARRAY_END;
|
||||
break;
|
||||
}
|
||||
if (isObjectEnd(c, &object_count)) {
|
||||
m_state = S_OBJECT_END;
|
||||
break;
|
||||
}
|
||||
if (c == ':') {
|
||||
m_state = S_COLON;
|
||||
break;
|
||||
}
|
||||
m_state = S_ERROR;
|
||||
break; // s_sting_end
|
||||
|
||||
case S_VARIABLE_START:
|
||||
if (c == '\"') {
|
||||
m_state = S_VARIABLE_END;
|
||||
break;
|
||||
}
|
||||
if (encoded) { // url_encoded quote
|
||||
status = isAlignedPrefix(quoteString, quoteStringLen, buf + i, len - i);
|
||||
if (status >= 0) {
|
||||
m_state = S_VARIABLE_END;
|
||||
encoded = true;
|
||||
i += status - 1;
|
||||
break;
|
||||
} else {
|
||||
m_state = S_ERROR;
|
||||
}
|
||||
}
|
||||
m_state = S_VARIABLE_BODY;
|
||||
break; // S_VARIABLE_START
|
||||
|
||||
case S_VARIABLE_BODY:
|
||||
if (c == '\"') {
|
||||
if (buf[i - 1] == '\\' && buf[i - 2] != '\\') {
|
||||
m_state = S_VARIABLE_BODY;
|
||||
break;
|
||||
} else {
|
||||
m_state = S_VARIABLE_END;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (encoded) { // url_encoded quote
|
||||
status = isAlignedPrefix(quoteString, quoteStringLen, buf + i, len - i);
|
||||
if (status >= 0) {
|
||||
m_state = S_VARIABLE_END;
|
||||
encoded = true;
|
||||
i += status - 1;
|
||||
break;
|
||||
} else {
|
||||
m_state = S_ERROR;
|
||||
}
|
||||
}
|
||||
m_state = S_VARIABLE_BODY;
|
||||
break; // S_VARIABLE_BODY
|
||||
|
||||
case S_VARIABLE_END:
|
||||
if (isspace(c)) {
|
||||
break;
|
||||
}
|
||||
if (c == ':') {
|
||||
m_state = S_COLON;
|
||||
break;
|
||||
}
|
||||
m_state = S_ERROR;
|
||||
break; // S_VARIABLE_END
|
||||
|
||||
case S_COMMA:
|
||||
if (isObjectStart(c, &object_count)) {
|
||||
m_state = S_OBJECT_START;
|
||||
break;
|
||||
}
|
||||
if (isArrayStart(c, &array_count)) {
|
||||
m_state = S_ARRAY_START;
|
||||
break;
|
||||
}
|
||||
if (isdigit(c)) {
|
||||
m_state = S_NUMBER;
|
||||
break;
|
||||
}
|
||||
if (c == '-') {
|
||||
if (i + 1 == len) { // End of buffer case
|
||||
m_state = S_NUMBER;
|
||||
break;
|
||||
}
|
||||
if (i + 1 < len && isdigit(buf[i + 1])) {
|
||||
m_state = S_NUMBER;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
m_state = S_ERROR;
|
||||
break;
|
||||
}
|
||||
if (isspace(c)) {
|
||||
break;
|
||||
}
|
||||
if (c == '\"') {
|
||||
m_state = S_STRING_START;
|
||||
break;
|
||||
}
|
||||
status = isAlignedPrefix(quoteString, quoteStringLen, buf + i, len - i);
|
||||
if (status >= 0) {
|
||||
m_state = S_STRING_START;
|
||||
encoded = true;
|
||||
i += status - 1;
|
||||
break;
|
||||
} else {
|
||||
m_state = S_ERROR;
|
||||
}
|
||||
status = isBoolean(buf + i, len - i);
|
||||
if (status >= 0) {
|
||||
m_state = S_BOOLEAN;
|
||||
i += status - 1;
|
||||
break;
|
||||
}
|
||||
m_state = S_ERROR;
|
||||
break; // S_COMMA
|
||||
|
||||
case S_COLON:
|
||||
if (isObjectStart(c, &object_count)) {
|
||||
m_state = S_OBJECT_START;
|
||||
break;
|
||||
}
|
||||
if (isArrayStart(c, &array_count)) {
|
||||
m_state = S_ARRAY_START;
|
||||
break;
|
||||
}
|
||||
if (isArrayEnd(c, &array_count)) {
|
||||
m_state = S_ARRAY_END;
|
||||
break;
|
||||
}
|
||||
if (isdigit(c)) {
|
||||
m_state = S_NUMBER;
|
||||
break;
|
||||
}
|
||||
if (c == '-') {
|
||||
if (i + 1 == len) { // End of buffer case
|
||||
m_state = S_NUMBER;
|
||||
break;
|
||||
}
|
||||
if (i + 1 < len && isdigit(buf[i + 1])) {
|
||||
m_state = S_NUMBER;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
m_state = S_ERROR;
|
||||
break;
|
||||
}
|
||||
if (isspace(c)) {
|
||||
break;
|
||||
}
|
||||
if (c == '\"') {
|
||||
m_state = S_STRING_START;
|
||||
break;
|
||||
}
|
||||
status = isAlignedPrefix(quoteString, quoteStringLen, buf + i, len - i);
|
||||
if (status >= 0) {
|
||||
m_state = S_STRING_START;
|
||||
encoded = true;
|
||||
i += status - 1;
|
||||
break;
|
||||
} else {
|
||||
m_state = S_ERROR;
|
||||
}
|
||||
status = isBoolean(buf + i, len - i);
|
||||
if (status >= 0) {
|
||||
m_state = S_BOOLEAN;
|
||||
i += status - 1;
|
||||
break;
|
||||
}
|
||||
m_state = S_ERROR;
|
||||
break; // S_COLON
|
||||
|
||||
case S_BOOLEAN:
|
||||
if (isspace(c)) {
|
||||
break;
|
||||
}
|
||||
if (c == ',') {
|
||||
m_state = S_COMMA;
|
||||
break;
|
||||
}
|
||||
if (isArrayEnd(c, &array_count)) {
|
||||
m_state = S_ARRAY_END;
|
||||
break;
|
||||
}
|
||||
if (isObjectEnd(c, &object_count)) {
|
||||
m_state = S_OBJECT_END;
|
||||
break;
|
||||
}
|
||||
m_state = S_ERROR;
|
||||
break; // S_BOOLEAN
|
||||
|
||||
case S_ERROR: break;
|
||||
case S_END: break;
|
||||
}
|
||||
if (m_state == S_ERROR) {
|
||||
return false;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (m_state != S_ERROR && array_count >= 0 && object_count >= 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Util
|
||||
} // namespace Waap
|
Reference in New Issue
Block a user