summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Feist <james.feist@linux.intel.com>2020-03-28 02:28:59 +0300
committerJames Feist <james.feist@linux.intel.com>2020-03-31 23:31:10 +0300
commitf0af8594734a83a242d7a2af7accbd5ba45df1d9 (patch)
tree6c8bebc35e249f000a9d1ad6d431e1e87581b025
parentc6f4e01779afb7a6eb25be15003829b46f81ba4c (diff)
downloadbmcweb-f0af8594734a83a242d7a2af7accbd5ba45df1d9.tar.xz
Protect against slow read attack
Right now as long as an attacker continutes to do a slow read, the connection will stay open forever. Set a timeout so this can't happen. Tested: Used slowhttptest to verify this wouldn't happen Change-Id: I4dbe2a18f9ccce0ba36875572ec3df6bf3be6a1e Signed-off-by: James Feist <james.feist@linux.intel.com>
-rw-r--r--http/http_connection.h51
-rw-r--r--http/timer_queue.h6
2 files changed, 33 insertions, 24 deletions
diff --git a/http/http_connection.h b/http/http_connection.h
index 4cd1e89e28..9f6c7b6676 100644
--- a/http/http_connection.h
+++ b/http/http_connection.h
@@ -831,34 +831,39 @@ class Connection : public std::enable_shared_from_this<
}
}
- void startDeadline()
+ void startDeadline(size_t timerIterations = 0)
{
+ // drop all connections after 1 minute, this time limit was chosen
+ // arbitrarily and can be adjusted later if needed
+ constexpr const size_t maxReadAttempts =
+ (60 / detail::timerQueueTimeoutSeconds);
+
cancelDeadlineTimer();
- timerCancelKey =
- timerQueue.add([this, self(shared_from_this()),
- readCount{parser->get().body().size()}] {
- // Mark timer as not active to avoid canceling it during
- // Connection destructor which leads to double free issue
- timerCancelKey.reset();
- if (!isAlive())
- {
- return;
- }
+ timerCancelKey = timerQueue.add([this, self(shared_from_this()),
+ readCount{parser->get().body().size()},
+ timerIterations{timerIterations + 1}] {
+ // Mark timer as not active to avoid canceling it during
+ // Connection destructor which leads to double free issue
+ timerCancelKey.reset();
+ if (!isAlive())
+ {
+ return;
+ }
- // Restart timer if read is in progress.
- // With threshold can be used to drop slow connections
- // to protect against slow-rate DoS attack
- if (parser->get().body().size() > readCount)
- {
- BMCWEB_LOG_DEBUG << this
- << " restart timer - read in progress";
- startDeadline();
- return;
- }
+ // Restart timer if read is in progress.
+ // With threshold can be used to drop slow connections
+ // to protect against slow-rate DoS attack
+ if ((parser->get().body().size() > readCount) &&
+ (timerIterations < maxReadAttempts))
+ {
+ BMCWEB_LOG_DEBUG << this << " restart timer - read in progress";
+ startDeadline(timerIterations);
+ return;
+ }
- close();
- });
+ close();
+ });
BMCWEB_LOG_DEBUG << this << " timer added: " << &timerQueue << ' '
<< *timerCancelKey;
}
diff --git a/http/timer_queue.h b/http/timer_queue.h
index 7339d66aea..d7a427ea87 100644
--- a/http/timer_queue.h
+++ b/http/timer_queue.h
@@ -11,6 +11,9 @@ namespace crow
{
namespace detail
{
+
+constexpr const size_t timerQueueTimeoutSeconds = 5;
+
// fast timer queue for fixed tick value.
class TimerQueue
{
@@ -49,7 +52,8 @@ class TimerQueue
// remove canceled ones immediately
if (x.second)
{
- if (now - x.first < std::chrono::seconds(5))
+ if (now - x.first <
+ std::chrono::seconds(timerQueueTimeoutSeconds))
{
break;
}