-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3001 from SpiderLabs/v3/dev/action_expirevar
V3/dev/action expirevar
- Loading branch information
Showing
24 changed files
with
5,526 additions
and
5,077 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
/* | ||
* ModSecurity, http://www.modsecurity.org/ | ||
* Copyright (c) 2023 Trustwave Holdings, Inc. (http://www.trustwave.com/) | ||
* | ||
* You may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* If any of the files related to licensing are missing or if you have any | ||
* other questions related to licensing please contact Trustwave Holdings, Inc. | ||
* directly using the email address security@modsecurity.org. | ||
* | ||
*/ | ||
|
||
#include "src/actions/expire_var.h" | ||
|
||
#include <string> | ||
|
||
#include "modsecurity/rules_set.h" | ||
#include "modsecurity/transaction.h" | ||
#include "modsecurity/rule.h" | ||
#include "src/utils/string.h" | ||
#include "src/variables/global.h" | ||
#include "src/variables/ip.h" | ||
#include "src/variables/resource.h" | ||
#include "src/variables/session.h" | ||
#include "src/variables/user.h" | ||
#include "src/variables/variable.h" | ||
|
||
namespace modsecurity { | ||
namespace actions { | ||
|
||
|
||
bool ExpireVar::init(std::string *error) { | ||
return true; | ||
} | ||
|
||
|
||
bool ExpireVar::evaluate(RuleWithActions *rule, Transaction *t) { | ||
|
||
std::string expireExpressionExpanded(m_string->evaluate(t)); | ||
|
||
std::string fully_qualified_var; | ||
int expirySeconds = 0; | ||
size_t posEquals = expireExpressionExpanded.find("="); | ||
if (posEquals == std::string::npos) { | ||
fully_qualified_var = expireExpressionExpanded; | ||
} else { | ||
fully_qualified_var = expireExpressionExpanded.substr(0, posEquals); | ||
std::string expiry = expireExpressionExpanded.substr(posEquals+1); | ||
if (expiry.find_first_not_of("0123456789") == std::string::npos) { | ||
expirySeconds = atoi(expiry.c_str()); | ||
} else { | ||
ms_dbg_a(t, 5, "Non-numeric expiry seconds found in expirevar expression."); | ||
return true; | ||
} | ||
} | ||
|
||
size_t posDot = fully_qualified_var.find("."); | ||
if (posDot == std::string::npos) { | ||
ms_dbg_a(t, 5, "No collection found in expirevar expression."); | ||
return true; | ||
} | ||
|
||
std::string collection = fully_qualified_var.substr(0, posDot); | ||
std::string variable_name = fully_qualified_var.substr(posDot+1); | ||
std::unique_ptr<RunTimeString> runTimeString(new RunTimeString()); | ||
runTimeString->appendText(fully_qualified_var); | ||
|
||
if (collection == "ip") { | ||
std::unique_ptr<modsecurity::variables::Ip_DynamicElement> ip_dynamicElement(new modsecurity::variables::Ip_DynamicElement(std::move(runTimeString))); | ||
ip_dynamicElement->setExpiry(t, variable_name, expirySeconds); | ||
} else if (collection == "global") { | ||
std::unique_ptr<modsecurity::variables::Global_DynamicElement> global_dynamicElement(new modsecurity::variables::Global_DynamicElement(std::move(runTimeString))); | ||
global_dynamicElement->setExpiry(t, variable_name, expirySeconds); | ||
} else if (collection == "resource") { | ||
std::unique_ptr<modsecurity::variables::Resource_DynamicElement> resource_dynamicElement(new modsecurity::variables::Resource_DynamicElement(std::move(runTimeString))); | ||
resource_dynamicElement->setExpiry(t, variable_name, expirySeconds); | ||
} else if (collection == "session") { | ||
std::unique_ptr<modsecurity::variables::Session_DynamicElement> session_dynamicElement(new modsecurity::variables::Session_DynamicElement(std::move(runTimeString))); | ||
session_dynamicElement->setExpiry(t, variable_name, expirySeconds); | ||
} else if (collection == "user") { | ||
std::unique_ptr<modsecurity::variables::User_DynamicElement> user_dynamicElement(new modsecurity::variables::User_DynamicElement(std::move(runTimeString))); | ||
user_dynamicElement->setExpiry(t, variable_name, expirySeconds); | ||
} else { | ||
ms_dbg_a(t, 5, "Invalid collection found in expirevar expression: collection must be `ip', `global', `resource', `user' or `session'"); | ||
} | ||
ms_dbg_a(t, 9, "Setting variable `" + variable_name + "' to expire in " + std::to_string(expirySeconds) + " seconds."); | ||
|
||
return true; | ||
} | ||
|
||
} // namespace actions | ||
} // namespace modsecurity |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/* | ||
* ModSecurity, http://www.modsecurity.org/ | ||
* Copyright (c) 2023 Trustwave Holdings, Inc. (http://www.trustwave.com/) | ||
* | ||
* You may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* If any of the files related to licensing are missing or if you have any | ||
* other questions related to licensing please contact Trustwave Holdings, Inc. | ||
* directly using the email address security@modsecurity.org. | ||
* | ||
*/ | ||
|
||
#include <memory> | ||
#include <string> | ||
#include <utility> | ||
|
||
#include "modsecurity/actions/action.h" | ||
#include "src/run_time_string.h" | ||
|
||
#ifndef SRC_ACTIONS_EXPIRE_VAR_H_ | ||
#define SRC_ACTIONS_EXPIRE_VAR_H_ | ||
|
||
class Transaction; | ||
|
||
namespace modsecurity { | ||
class Transaction; | ||
class RuleWithOperator; | ||
|
||
namespace actions { | ||
|
||
class ExpireVar : public Action { | ||
public: | ||
explicit ExpireVar(const std::string &action) : Action(action) { } | ||
|
||
explicit ExpireVar(std::unique_ptr<RunTimeString> z) | ||
: Action("expirevar", RunTimeOnlyIfMatchKind), | ||
m_string(std::move(z)) { } | ||
|
||
bool evaluate(RuleWithActions *rule, Transaction *transaction) override; | ||
bool init(std::string *error) override; | ||
|
||
private: | ||
|
||
std::unique_ptr<RunTimeString> m_string; | ||
}; | ||
|
||
} // namespace actions | ||
} // namespace modsecurity | ||
|
||
|
||
#endif // SRC_ACTIONS_EXPIRE_VAR_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
/* | ||
* ModSecurity, http://www.modsecurity.org/ | ||
* Copyright (c) 2023 Trustwave Holdings, Inc. (http://www.trustwave.com/) | ||
* | ||
* You may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* If any of the files related to licensing are missing or if you have any | ||
* other questions related to licensing please contact Trustwave Holdings, Inc. | ||
* directly using the email address security@modsecurity.org. | ||
* | ||
*/ | ||
|
||
#include "src/collection/backend/collection_data.h" | ||
|
||
|
||
namespace modsecurity { | ||
namespace collection { | ||
namespace backend { | ||
|
||
|
||
bool CollectionData::isExpired() const { | ||
if (m_hasExpiryTime == false) { | ||
return false; | ||
} | ||
auto now = std::chrono::system_clock::now(); | ||
return (now >= m_expiryTime); | ||
} | ||
|
||
|
||
void CollectionData::setExpiry(int32_t seconds_until_expiry) { | ||
m_expiryTime = std::chrono::system_clock::now() + std::chrono::seconds(seconds_until_expiry); | ||
m_hasExpiryTime = true; | ||
} | ||
|
||
std::string CollectionData::getSerialized() const { | ||
std::string serialized; | ||
if (hasValue()) { | ||
serialized.reserve(30 + 10 + getValue().size()); | ||
} else { | ||
serialized.reserve(16+10); | ||
} | ||
|
||
serialized.assign("{"); | ||
|
||
if (hasExpiry()) { | ||
serialized.append("\"__expire_\":"); | ||
uint64_t expiryEpochSeconds = std::chrono::duration_cast<std::chrono::seconds>(m_expiryTime.time_since_epoch()).count(); | ||
serialized.append(std::to_string(expiryEpochSeconds)); | ||
if (hasValue()) { | ||
serialized.append(","); | ||
} | ||
} | ||
if (hasValue()) { | ||
serialized.append("\"__value_\":\""); | ||
serialized.append(getValue()); | ||
serialized.append("\""); | ||
} | ||
|
||
serialized.append("}"); | ||
|
||
return serialized; | ||
} | ||
|
||
void CollectionData::setFromSerialized(const char* serializedData, size_t length) { | ||
const static std::string expiryPrefix("\"__expire_\":"); | ||
const static std::string valuePrefix("\"__value_\":\""); | ||
m_hasValue = false; | ||
m_hasExpiryTime = false; | ||
|
||
std::string serializedString(serializedData, length); | ||
if ((serializedString.find("{") == 0) && (serializedString.substr(serializedString.length()-1) == "}")) { | ||
size_t currentPos = 1; | ||
uint64_t expiryEpochSeconds = 0; | ||
bool invalidSerializedFormat = false; | ||
bool doneParsing = false; | ||
|
||
// Extract the expiry time, if it exists | ||
if (serializedString.find(expiryPrefix, currentPos) == currentPos) { | ||
currentPos += expiryPrefix.length(); | ||
std::string expiryDigits = serializedString.substr(currentPos, 10); | ||
if (expiryDigits.find_first_not_of("0123456789") == std::string::npos) { | ||
expiryEpochSeconds = strtoll(expiryDigits.c_str(), NULL, 10); | ||
} else { | ||
invalidSerializedFormat = true; | ||
} | ||
currentPos += 10; | ||
} | ||
|
||
if ((!invalidSerializedFormat) && (expiryEpochSeconds > 0)) { | ||
if (serializedString.find(",", currentPos) == currentPos) { | ||
currentPos++; | ||
} else if (currentPos == serializedString.length()-1) { | ||
doneParsing = true; | ||
} else { | ||
invalidSerializedFormat = true; | ||
} | ||
} | ||
|
||
if ((!invalidSerializedFormat) && (!doneParsing)) { | ||
// Extract the value | ||
if ((serializedString.find(valuePrefix, currentPos) == currentPos)) { | ||
currentPos += valuePrefix.length(); | ||
size_t expectedCloseQuotePos = serializedString.length() - 2; | ||
if ((serializedString.substr(expectedCloseQuotePos, 1) == "\"") && (expectedCloseQuotePos >= currentPos)) { | ||
m_value = serializedString.substr(currentPos); | ||
m_value.resize(m_value.length()-2); | ||
m_hasValue = true; | ||
} else { | ||
invalidSerializedFormat = true; | ||
} | ||
} else { | ||
invalidSerializedFormat = true; | ||
} | ||
} | ||
|
||
// Set the object's expiry time, if we found one | ||
if ((!invalidSerializedFormat) && (expiryEpochSeconds > 0)) { | ||
std::chrono::seconds expiryDuration(expiryEpochSeconds); | ||
std::chrono::system_clock::time_point expiryTimePoint(expiryDuration); | ||
m_expiryTime = expiryTimePoint; | ||
m_hasExpiryTime = true; | ||
} | ||
if (!invalidSerializedFormat) { | ||
return; | ||
} | ||
} | ||
|
||
// this is the residual case; the entire string is a simple value (not JSON-ish encoded) | ||
// the foreseen case here is lmdb content from prior to the serialization support | ||
m_value.assign(serializedData, length); | ||
m_hasValue = true; | ||
return; | ||
} | ||
|
||
} // namespace backend | ||
} // namespace collection | ||
} // namespace modsecurity |
Oops, something went wrong.