Relaxed login throttler: now have 5 attempts before being throttled. fixes #302
This commit is contained in:
@@ -54,7 +54,7 @@ LoginThrottler::removeOutdatedEntries()
|
|||||||
|
|
||||||
for (auto it {std::begin(_attemptsInfo)}; it != std::end(_attemptsInfo); )
|
for (auto it {std::begin(_attemptsInfo)}; it != std::end(_attemptsInfo); )
|
||||||
{
|
{
|
||||||
if (it->second <= now)
|
if (it->second.nextAttempt <= now)
|
||||||
it = _attemptsInfo.erase(it);
|
it = _attemptsInfo.erase(it);
|
||||||
else
|
else
|
||||||
++it;
|
++it;
|
||||||
@@ -65,7 +65,6 @@ void
|
|||||||
LoginThrottler::onBadClientAttempt(const boost::asio::ip::address& address)
|
LoginThrottler::onBadClientAttempt(const boost::asio::ip::address& address)
|
||||||
{
|
{
|
||||||
const boost::asio::ip::address clientAddress {getAddressToThrottle(address)};
|
const boost::asio::ip::address clientAddress {getAddressToThrottle(address)};
|
||||||
|
|
||||||
const Wt::WDateTime now {Wt::WDateTime::currentDateTime()};
|
const Wt::WDateTime now {Wt::WDateTime::currentDateTime()};
|
||||||
|
|
||||||
if (_attemptsInfo.size() >= _maxEntries)
|
if (_attemptsInfo.size() >= _maxEntries)
|
||||||
@@ -73,9 +72,25 @@ LoginThrottler::onBadClientAttempt(const boost::asio::ip::address& address)
|
|||||||
if (_attemptsInfo.size() >= _maxEntries)
|
if (_attemptsInfo.size() >= _maxEntries)
|
||||||
_attemptsInfo.erase(Random::pickRandom(_attemptsInfo));
|
_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
|
void
|
||||||
@@ -95,7 +110,10 @@ LoginThrottler::isClientThrottled(const boost::asio::ip::address& address) const
|
|||||||
if (it == _attemptsInfo.end())
|
if (it == _attemptsInfo.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return it->second > Wt::WDateTime::currentDateTime();
|
if (!it->second.nextAttempt.isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return it->second.nextAttempt > Wt::WDateTime::currentDateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // Auth
|
} // Auth
|
||||||
|
|||||||
@@ -19,8 +19,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <shared_mutex>
|
#include <chrono>
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <Wt/WDateTime.h>
|
#include <Wt/WDateTime.h>
|
||||||
@@ -44,8 +43,15 @@ namespace Auth
|
|||||||
void removeOutdatedEntries();
|
void removeOutdatedEntries();
|
||||||
|
|
||||||
const std::size_t _maxEntries;
|
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
|
} // Auth
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user