mirror of
https://github.com/openappsec/openappsec.git
synced 2025-06-28 16:41:02 +03:00
227 lines
6.2 KiB
C++
Executable File
227 lines
6.2 KiB
C++
Executable File
// 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 "FpMitigation.h"
|
|
#include <memory>
|
|
#include <algorithm>
|
|
#include <string.h>
|
|
|
|
|
|
#define DEFAULT_SCORE 10.0
|
|
#define TRUE_POSITIVE_REPUTATION_THRESHOLD 1.5
|
|
#define FALSE_POSITIVE_REPUTATION_THRESHOLD 5
|
|
|
|
USE_DEBUG_FLAG(D_WAAP);
|
|
|
|
using namespace std::chrono;
|
|
|
|
FpMitigationScore::FpMitigationScore(const std::string& backupFilePath) :
|
|
SerializeToFilePeriodically(duration_cast<seconds>(minutes(10)), backupFilePath),
|
|
m_policyDataUrl(),
|
|
m_policyDataParam(),
|
|
m_history(),
|
|
m_counter(0)
|
|
{
|
|
dbgTrace(D_WAAP) << "False positive mitigation constructor";
|
|
restore();
|
|
}
|
|
|
|
FpMitigationScore::~FpMitigationScore()
|
|
{
|
|
reset();
|
|
}
|
|
|
|
void FpMitigationScore::reset() {
|
|
m_policyDataParam.clear();
|
|
|
|
m_policyDataUrl.clear();
|
|
|
|
m_history.clear();
|
|
}
|
|
|
|
void FpMitigationScore::serialize(std::ostream& stream) {
|
|
cereal::JSONOutputArchive archive(stream);
|
|
|
|
archive(cereal::make_nvp("version", 1),
|
|
cereal::make_nvp("policyDataUrl", m_policyDataUrl),
|
|
cereal::make_nvp("policyDataParam", m_policyDataParam));
|
|
}
|
|
|
|
void FpMitigationScore::deserialize(std::istream& stream) {
|
|
cereal::JSONInputArchive archive(stream);
|
|
|
|
size_t version = 0;
|
|
|
|
try
|
|
{
|
|
archive(cereal::make_nvp("version", version));
|
|
}
|
|
catch (std::runtime_error & e) {
|
|
archive.setNextName(nullptr);
|
|
version = 0;
|
|
dbgDebug(D_WAAP) << "Can't load file version: " << e.what();
|
|
}
|
|
|
|
switch (version)
|
|
{
|
|
case 0:
|
|
archive(cereal::make_nvp("m_policyDataUrl", m_policyDataUrl),
|
|
cereal::make_nvp("m_policyDataParam", m_policyDataParam));
|
|
break;
|
|
case 1:
|
|
archive(cereal::make_nvp("policyDataUrl", m_policyDataUrl),
|
|
cereal::make_nvp("policyDataParam", m_policyDataParam));
|
|
break;
|
|
default:
|
|
dbgWarning(D_WAAP) << "unknown file format version: " << version;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
double FpMitigationScore::calculateFpMitigationScore(const std::string& shortUri,
|
|
const std::string& canonisedParam)
|
|
{
|
|
double urlScore = DEFAULT_SCORE, paramScore = DEFAULT_SCORE;
|
|
|
|
if (m_policyDataUrl.find(shortUri) != m_policyDataUrl.end())
|
|
{
|
|
urlScore = m_policyDataUrl[shortUri]->getScore();
|
|
}
|
|
|
|
if (m_policyDataParam.find(canonisedParam) != m_policyDataParam.end())
|
|
{
|
|
paramScore = m_policyDataParam[canonisedParam]->getScore();
|
|
}
|
|
|
|
return ((int)(paramScore * 2) / 3 + 3.3) * ((int)(urlScore * 2) / 3 + 3.3) / 10;
|
|
}
|
|
|
|
template<typename T>
|
|
bool hasElement(std::vector<T> vec, T& elem) {
|
|
return (std::find(vec.begin(), vec.end(), elem) != vec.end());
|
|
}
|
|
|
|
void FpMitigationScore::learnFalsePositive(
|
|
const std::vector<std::string>& keywordMatches,
|
|
PolicyCounterType rep,
|
|
const std::string& shortUri,
|
|
const std::string& canonisedParam)
|
|
{
|
|
static std::string probing = "probing";
|
|
|
|
if (keywordMatches.size() > 3 && hasElement(keywordMatches, probing))
|
|
{
|
|
return;
|
|
}
|
|
if (rep != UNKNOWN_TYPE)
|
|
{
|
|
if (m_policyDataUrl.find(shortUri) == m_policyDataUrl.end())
|
|
{
|
|
m_policyDataUrl[shortUri] = std::make_shared<PolicyDataCounter>();
|
|
}
|
|
if (m_policyDataParam.find(canonisedParam) == m_policyDataParam.end())
|
|
{
|
|
m_policyDataParam[canonisedParam] = std::make_shared<PolicyDataCounter>();
|
|
}
|
|
|
|
incrementCounter(shortUri, canonisedParam, rep);
|
|
m_counter++;
|
|
|
|
if (m_counter % FP_SCORE_CALCULATION_INTERVALS == 0)
|
|
{
|
|
dbgTrace(D_WAAP) << "evaluating fp mitigation scores";
|
|
evaluatePolicyDataCounterScore();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
PolicyCounterType FpMitigationScore::IdentifyFalseTruePositive(double relativeReputation,
|
|
const std::string& shortUri, const std::string& canonisedParam, const std::string& userAgentIp)
|
|
{
|
|
std::string uriParamCat = shortUri + canonisedParam;
|
|
if (relativeReputation < TRUE_POSITIVE_REPUTATION_THRESHOLD && m_history.find(uriParamCat) == m_history.end())
|
|
{
|
|
m_history.insert(uriParamCat);
|
|
return TRUE_POSITIVE;
|
|
}
|
|
if (relativeReputation > FALSE_POSITIVE_REPUTATION_THRESHOLD && m_history.find(userAgentIp) == m_history.end())
|
|
{
|
|
m_history.insert(userAgentIp);
|
|
return FALSE_POSITIVE;
|
|
}
|
|
|
|
return UNKNOWN_TYPE;
|
|
}
|
|
|
|
void FpMitigationScore::incrementCounter(const std::string& shortUri,
|
|
const std::string& canonisedParam,
|
|
PolicyCounterType counterType)
|
|
{
|
|
// It is assumed that m_policyDataUrl contains shortUrl and
|
|
// m_policyDataParam contains canonisedParam. See caller.
|
|
std::shared_ptr<PolicyDataCounter> urlCounter = m_policyDataUrl[shortUri];
|
|
std::shared_ptr<PolicyDataCounter> paramCounter = m_policyDataParam[canonisedParam];
|
|
|
|
urlCounter->incrementCounter(counterType);
|
|
paramCounter->incrementCounter(counterType);
|
|
}
|
|
|
|
void FpMitigationScore::evaluatePolicyDataCounterScore()
|
|
{
|
|
for (auto urlPolicy : m_policyDataUrl) {
|
|
urlPolicy.second->evaluateScore();
|
|
}
|
|
|
|
for (auto paramPolicy : m_policyDataParam) {
|
|
paramPolicy.second->evaluateScore();
|
|
}
|
|
}
|
|
|
|
PolicyDataCounter::PolicyDataCounter() : falsePositive(0), truePositive(0), score(10.0)
|
|
{
|
|
}
|
|
|
|
double PolicyDataCounter::getScore()
|
|
{
|
|
return score;
|
|
}
|
|
|
|
void PolicyDataCounter::incrementCounter(PolicyCounterType counterType)
|
|
{
|
|
switch (counterType)
|
|
{
|
|
case UNKNOWN_TYPE:
|
|
// add assert
|
|
break;
|
|
case FALSE_POSITIVE:
|
|
case HTML_CONTENT:
|
|
falsePositive++;
|
|
break;
|
|
case TRUE_POSITIVE:
|
|
case SPAM:
|
|
truePositive++;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void PolicyDataCounter::evaluateScore()
|
|
{
|
|
size_t tp = truePositive + 50 + 1, fp = falsePositive;
|
|
score = (double)(10.0 * tp) / (10.0 * fp + tp);
|
|
}
|