Relaxed login throttler: now have 5 attempts before being throttled. fixes #302

This commit is contained in:
emeric
2023-01-20 21:26:19 +01:00
parent 69f7b89d33
commit 97c083523f
2 changed files with 32 additions and 8 deletions
+23 -5
View File
@@ -54,7 +54,7 @@ LoginThrottler::removeOutdatedEntries()
for (auto it {std::begin(_attemptsInfo)}; it != std::end(_attemptsInfo); )
{
if (it->second <= now)
if (it->second.nextAttempt <= now)
it = _attemptsInfo.erase(it);
else
++it;
@@ -65,7 +65,6 @@ void
LoginThrottler::onBadClientAttempt(const boost::asio::ip::address& address)
{
const boost::asio::ip::address clientAddress {getAddressToThrottle(address)};
const Wt::WDateTime now {Wt::WDateTime::currentDateTime()};
if (_attemptsInfo.size() >= _maxEntries)
@@ -73,9 +72,25 @@ LoginThrottler::onBadClientAttempt(const boost::asio::ip::address& address)
if (_attemptsInfo.size() >= _maxEntries)
_attemptsInfo.erase(Random::pickRandom(_attemptsInfo));
_attemptsInfo[address] = now.addSecs(3);
AttemptInfo& attemptInfo {_attemptsInfo[address]};
if (attemptInfo.nextAttempt.isValid())
{
assert(attemptInfo.nextAttempt <= now); // should not be called if throttled
attemptInfo = {};
}
LMS_LOG(AUTH, DEBUG) << "Registering bad attempt for '" << clientAddress.to_string() << "'";
attemptInfo.badConsecutiveAttemptCount += 1;
LMS_LOG(AUTH, DEBUG) << "Registering bad attempt for '" << clientAddress.to_string() << "', consecutive bad attempts count = " << attemptInfo.badConsecutiveAttemptCount;
if (attemptInfo.badConsecutiveAttemptCount >= _maxBadConsecutiveAttemptCount)
{
LMS_LOG(AUTH, DEBUG) << "Throttling '" << clientAddress.to_string() << "'";
attemptInfo.nextAttempt = now.addMSecs(std::chrono::duration_cast<std::chrono::milliseconds>(_throttlingDuration).count());
}
else
{
attemptInfo.nextAttempt = {};
}
}
void
@@ -95,7 +110,10 @@ LoginThrottler::isClientThrottled(const boost::asio::ip::address& address) const
if (it == _attemptsInfo.end())
return false;
return it->second > Wt::WDateTime::currentDateTime();
if (!it->second.nextAttempt.isValid())
return false;
return it->second.nextAttempt > Wt::WDateTime::currentDateTime();
}
} // Auth
@@ -19,8 +19,7 @@
#pragma once
#include <shared_mutex>
#include <string>
#include <chrono>
#include <unordered_map>
#include <Wt/WDateTime.h>
@@ -44,8 +43,15 @@ namespace Auth
void removeOutdatedEntries();
const std::size_t _maxEntries;
static constexpr std::size_t _maxBadConsecutiveAttemptCount {5};
static constexpr std::chrono::seconds _throttlingDuration {3};
std::unordered_map<boost::asio::ip::address, Wt::WDateTime> _attemptsInfo;
struct AttemptInfo
{
Wt::WDateTime nextAttempt;
std::size_t badConsecutiveAttemptCount{};
};
std::unordered_map<boost::asio::ip::address, AttemptInfo> _attemptsInfo;
};
} // Auth