// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved. // Licensed under the Apache License, Version 2.0 (the "License"); // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "WaapConfigBase.h" #include #include "WaapConfigApplication.h" #include "WaapOverride.h" #include "WaapTrigger.h" #include "WaapOpenRedirectPolicy.h" #include "CsrfPolicy.h" #include "WaapErrorDisclosurePolicy.h" #include "TrustedSources.h" #include "Waf2Util.h" USE_DEBUG_FLAG(D_WAAP_ULIMITS); USE_DEBUG_FLAG(D_WAAP); USE_DEBUG_FLAG(D_OA_SCHEMA_UPDATER); using boost::algorithm::to_lower_copy; using namespace std; WaapConfigBase::WaapConfigBase() : m_assetId(""), m_autonomousSecurityLevel(""), m_autonomousSecurity(false), m_assetName(""), m_practiceId(""), m_practiceName(""), m_ruleId(""), m_ruleName(""), m_overridePolicy(nullptr), m_triggerPolicy(nullptr), m_trustedSourcesPolicy(nullptr), m_waapParameters(nullptr), m_openRedirectPolicy(nullptr), m_errorDisclosurePolicy(nullptr), m_csrfPolicy(nullptr), m_rateLimitingPolicy(nullptr), m_errorLimitingPolicy(nullptr), m_errorLimiting(nullptr), m_userLimitsPolicy(nullptr), m_securityHeadersPolicy(nullptr) { m_blockingLevel = BlockingLevel::NO_BLOCKING; } void WaapConfigBase::load(cereal::JSONInputArchive& ar) { readJSONByCereal(ar); loadTriggersPolicy(ar); loadOverridePolicy(ar); loadTrustedSourcesPolicy(ar); loadWaapParametersPolicy(ar); loadUserLimitsPolicy(ar); loadRateLimitingPolicy(ar); loadErrorLimitingPolicy(ar); } void WaapConfigBase::readJSONByCereal(cereal::JSONInputArchive& ar) { ar( cereal::make_nvp("webAttackMitigation", m_autonomousSecurity), cereal::make_nvp("webAttackMitigationAction", m_autonomousSecurityLevel), cereal::make_nvp("practiceId", m_practiceId), cereal::make_nvp("practiceName", m_practiceName), cereal::make_nvp("assetId", m_assetId), cereal::make_nvp("assetName", m_assetName), cereal::make_nvp("ruleId", m_ruleId), cereal::make_nvp("ruleName", m_ruleName) ); try { std::string application_urls; ar(cereal::make_nvp("applicationUrls", application_urls)); m_applicationUrls = split(application_urls, ';'); } catch (std::runtime_error& e) { dbgWarning(D_WAAP) << "Error to load applicationUrls field in policy" << e.what(); ar.setNextName(nullptr); } m_blockingLevel = blockingLevelBySensitivityStr(m_autonomousSecurityLevel); } void WaapConfigBase::loadCsrfPolicy(cereal::JSONInputArchive& ar) { std::string failMessage = "Failed to load the CSRF policy of the current rule: " + m_ruleName + ": "; try { m_csrfPolicy = std::make_shared(ar); } catch (std::runtime_error& e) { ar.setNextName(nullptr); dbgWarning(D_WAAP) << failMessage << e.what(); m_csrfPolicy = std::make_shared(); } } void WaapConfigBase::loadSecurityHeadersPolicy(cereal::JSONInputArchive& ar) { std::string failMessage = "Failed to load the Security Headers policy of the current rule: " + m_ruleName + ": "; try { m_securityHeadersPolicy = std::make_shared(ar); } catch (std::runtime_error& e) { ar.setNextName(nullptr); // Feature is currently not supported by the UI, thus changing debug level to debug. dbgDebug(D_WAAP) << failMessage << e.what(); m_securityHeadersPolicy = nullptr; } } void WaapConfigBase::loadOverridePolicy(cereal::JSONInputArchive& ar) { std::string failMessage = "Failed to load the WAAP Overrides of the current rule: " + m_ruleName + ": "; try { m_overridePolicy = std::make_shared(ar); } catch (std::runtime_error& e) { ar.setNextName(nullptr); dbgWarning(D_WAAP) << failMessage << e.what(); m_overridePolicy = nullptr; } } void WaapConfigBase::loadTriggersPolicy(cereal::JSONInputArchive& ar) { std::string failMessage = "Failed to load the WAAP Triggers of the current rule: " + m_ruleName + ": "; try { m_triggerPolicy = std::make_shared(ar); } catch (std::runtime_error& e) { ar.setNextName(nullptr); dbgWarning(D_WAAP) << failMessage << e.what(); m_triggerPolicy = nullptr; } } void WaapConfigBase::loadTrustedSourcesPolicy(cereal::JSONInputArchive& ar) { std::string failMessage = "Failed to load the WAAP Trusted sources of the current rule: " + m_ruleName + ": "; try { m_trustedSourcesPolicy = std::make_shared(ar); } catch (std::runtime_error & e) { ar.setNextName(nullptr); dbgWarning(D_WAAP) << failMessage << e.what(); m_trustedSourcesPolicy = nullptr; } } void WaapConfigBase::loadWaapParametersPolicy(cereal::JSONInputArchive& ar) { std::string failMessage = "Failed to load the WAAP Parameters of the current rule: " + m_ruleName + ": "; try { m_waapParameters = std::make_shared(ar); } catch (std::runtime_error & e) { ar.setNextName(nullptr); dbgWarning(D_WAAP) << failMessage << e.what(); m_waapParameters = nullptr; } } void WaapConfigBase::loadRateLimitingPolicy(cereal::JSONInputArchive& ar) { std::string failMessage = "Failed to load the WAAP Rate Limiting of the current rule: " + m_ruleName + ": "; try { m_rateLimitingPolicy = std::make_shared(ar); } catch (std::runtime_error & e) { ar.setNextName(nullptr); // Feature is currently not supported by the UI, thus changing debug level to debug. dbgDebug(D_WAAP) << failMessage << e.what(); m_rateLimitingPolicy = nullptr; } } void WaapConfigBase::loadErrorLimitingPolicy(cereal::JSONInputArchive& ar) { std::string failMessage = "Failed to load the WAAP Error Limiting of the current rule: " + m_ruleName + ": "; try { m_errorLimiting = std::make_shared(ar); std::shared_ptr policy; policy = std::make_shared(); policy->rules.push_back(Waap::RateLimiting::Policy::Rule()); policy->rules[0].rate.interval = m_errorLimiting->m_errorLimiterPolicy.interval; policy->rules[0].rate.events = m_errorLimiting->m_errorLimiterPolicy.events; policy->rules[0].uriFilter.groupBy = Waap::RateLimiting::Policy::Rule::UriFilter::GroupBy::GLOBAL; policy->rules[0].sourceFilter.groupBy = Waap::RateLimiting::Policy::Rule::SourceFilter::GroupBy::GLOBAL; policy->rules[0].uriFilter.scope = Waap::RateLimiting::Policy::Rule::UriFilter::Scope::ALL; policy->rules[0].sourceFilter.scope = Waap::RateLimiting::Policy::Rule::SourceFilter::Scope::ALL; policy->m_rateLimiting.enable = m_errorLimiting->getErrorLimitingEnforcementStatus(); if (m_errorLimiting->m_errorLimiterPolicy.type == "quarantine") { policy->rules[0].action.type = Waap::RateLimiting::Policy::Rule::Action::Type::QUARANTINE; policy->rules[0].action.quarantineTimeSeconds = m_errorLimiting->m_errorLimiterPolicy.blockingTime; } else if (m_errorLimiting->m_errorLimiterPolicy.type == "rate limit") { policy->rules[0].action.type = Waap::RateLimiting::Policy::Rule::Action::Type::RATE_LIMIT; } else if (m_errorLimiting->m_errorLimiterPolicy.type == "detect") { policy->rules[0].action.type = Waap::RateLimiting::Policy::Rule::Action::Type::DETECT; } m_errorLimitingPolicy = policy; } catch (std::runtime_error & e) { ar.setNextName(nullptr); // Feature is currently not supported by the UI, thus changing debug level to debug. dbgDebug(D_WAAP) << failMessage << e.what(); m_errorLimiting = nullptr; m_errorLimitingPolicy = nullptr; } } void WaapConfigBase::loadOpenRedirectPolicy(cereal::JSONInputArchive& ar) { std::string failMessage = "Failed to load the WAAP OpenRedirect policy"; try { m_openRedirectPolicy = std::make_shared(ar); } catch (std::runtime_error & e) { ar.setNextName(nullptr); dbgWarning(D_WAAP) << failMessage << e.what(); // TODO:: change the default back to nullptr when implemeted in hook // m_openRedirectPolicy = nullptr; // Now (until hook is implemented) the default is enabled+enforced m_openRedirectPolicy = std::make_shared(); } } const std::vector & WaapConfigBase::get_applicationUrls() const { return m_applicationUrls; } void WaapConfigBase::loadErrorDisclosurePolicy(cereal::JSONInputArchive& ar) { std::string failMessage = "Failed to load the WAAP Information Disclosure policy"; try { m_errorDisclosurePolicy = std::make_shared(ar); } catch (std::runtime_error & e) { ar.setNextName(nullptr); dbgWarning(D_WAAP) << failMessage << e.what(); m_errorDisclosurePolicy = nullptr; } } void WaapConfigBase::loadUserLimitsPolicy(cereal::JSONInputArchive& ar) { try { m_userLimitsPolicy = std::make_shared(ar); dbgInfo(D_WAAP_ULIMITS) << "[USER LIMITS] policy loaded:\n" << *m_userLimitsPolicy; } catch (std::runtime_error & e) { ar.setNextName(nullptr); m_userLimitsPolicy = std::make_shared(); dbgInfo(D_WAAP_ULIMITS) << "[USER LIMITS] default policy loaded:\n" << *m_userLimitsPolicy; } } bool WaapConfigBase::operator==(const WaapConfigBase& other) const { return m_autonomousSecurity == other.m_autonomousSecurity && m_autonomousSecurityLevel == other.m_autonomousSecurityLevel && m_practiceId == other.m_practiceId && m_practiceName == other.m_practiceName && m_ruleId == other.m_ruleId && m_ruleName == other.m_ruleName && m_assetId == other.m_assetId && m_assetName == other.m_assetName && Waap::Util::compareObjects(m_triggerPolicy, other.m_triggerPolicy) && Waap::Util::compareObjects(m_overridePolicy, other.m_overridePolicy) && Waap::Util::compareObjects(m_trustedSourcesPolicy, other.m_trustedSourcesPolicy) && Waap::Util::compareObjects(m_waapParameters, other.m_waapParameters) && Waap::Util::compareObjects(m_openRedirectPolicy, other.m_openRedirectPolicy) && Waap::Util::compareObjects(m_errorDisclosurePolicy, other.m_errorDisclosurePolicy) && Waap::Util::compareObjects(m_rateLimitingPolicy, other.m_rateLimitingPolicy) && Waap::Util::compareObjects(m_errorLimitingPolicy, other.m_errorLimitingPolicy) && Waap::Util::compareObjects(m_csrfPolicy, other.m_csrfPolicy) && Waap::Util::compareObjects(m_userLimitsPolicy, other.m_userLimitsPolicy) && Waap::Util::compareObjects(m_securityHeadersPolicy, other.m_securityHeadersPolicy); } void WaapConfigBase::printMe(std::ostream& os) const { os << m_autonomousSecurity << ", " << m_autonomousSecurityLevel; os << ", " << m_ruleId << ", " << m_ruleName; os << ", " << m_practiceId << ", " << m_practiceName << ", " << m_assetId << ", " << m_assetName; } const std::string& WaapConfigBase::get_AssetId() const { return m_assetId; } const std::string& WaapConfigBase::get_AssetName() const { return m_assetName; } const std::string& WaapConfigBase::get_PracticeIdByPactice(DecisionType practiceType) const { switch (practiceType) { case DecisionType::AUTONOMOUS_SECURITY_DECISION: return m_practiceId; default: dbgError(D_WAAP) << "Can't find practice type for practice ID by practice: " << practiceType << ", return web app practice ID"; return m_practiceId; } } const std::string& WaapConfigBase::get_PracticeNameByPactice(DecisionType practiceType) const { switch (practiceType) { case DecisionType::AUTONOMOUS_SECURITY_DECISION: return m_practiceName; default: dbgError(D_WAAP) << "Can't find practice type for practice name by practice: " << practiceType << ", return web app practice name"; return m_practiceName; } } const std::string& WaapConfigBase::get_RuleId() const { return m_ruleId; } const std::string& WaapConfigBase::get_RuleName() const { return m_ruleName; } const bool& WaapConfigBase::get_WebAttackMitigation() const { return m_autonomousSecurity; } const std::string& WaapConfigBase::get_WebAttackMitigationAction() const { return m_autonomousSecurityLevel; } AttackMitigationMode WaapConfigBase::get_WebAttackMitigationMode(const IWaapConfig& siteConfig) { AttackMitigationMode attackMitigationMode = AttackMitigationMode::UNKNOWN; if (siteConfig.get_WebAttackMitigation()) { attackMitigationMode = (siteConfig.get_BlockingLevel() == BlockingLevel::NO_BLOCKING) ? AttackMitigationMode::LEARNING : AttackMitigationMode::PREVENT; } else { attackMitigationMode = AttackMitigationMode::DISABLED; } return attackMitigationMode; } const char* WaapConfigBase::get_WebAttackMitigationModeStr(const IWaapConfig& siteConfig) { switch(get_WebAttackMitigationMode(siteConfig)) { case AttackMitigationMode::DISABLED: return "DISABLED"; case AttackMitigationMode::LEARNING: return "LEARNING"; case AttackMitigationMode::PREVENT: return "PREVENT"; default: return "UNKNOWN"; } } const BlockingLevel& WaapConfigBase::get_BlockingLevel() const { return m_blockingLevel; } const std::shared_ptr& WaapConfigBase::get_OverridePolicy() const { return m_overridePolicy; } const std::shared_ptr& WaapConfigBase::get_TriggerPolicy() const { return m_triggerPolicy; } const std::shared_ptr& WaapConfigBase::get_TrustedSourcesPolicy() const { return m_trustedSourcesPolicy; } const std::shared_ptr& WaapConfigBase::get_CsrfPolicy() const { return m_csrfPolicy; } const std::shared_ptr& WaapConfigBase::get_WaapParametersPolicy() const { return m_waapParameters; } const std::shared_ptr& WaapConfigBase::get_RateLimitingPolicy() const { return m_rateLimitingPolicy; } const std::shared_ptr& WaapConfigBase::get_ErrorLimitingPolicy() const { return m_errorLimitingPolicy; } const std::shared_ptr& WaapConfigBase::get_OpenRedirectPolicy() const { return m_openRedirectPolicy; } const std::shared_ptr& WaapConfigBase::get_ErrorDisclosurePolicy() const { return m_errorDisclosurePolicy; } const std::shared_ptr& WaapConfigBase::get_SecurityHeadersPolicy() const { return m_securityHeadersPolicy; } const std::shared_ptr& WaapConfigBase::get_UserLimitsPolicy() const { return m_userLimitsPolicy; } BlockingLevel WaapConfigBase::blockingLevelBySensitivityStr(const std::string& sensitivity) const { std::string sensitivityLower = to_lower_copy(sensitivity); if (sensitivityLower == "transparent") { return BlockingLevel::NO_BLOCKING; } else if (sensitivityLower == "low") { return BlockingLevel::LOW_BLOCKING_LEVEL; } else if (sensitivityLower == "balanced") { return BlockingLevel::MEDIUM_BLOCKING_LEVEL; } else if (sensitivityLower == "high") { return BlockingLevel::HIGH_BLOCKING_LEVEL; } return BlockingLevel::NO_BLOCKING; }