From 48ec718a6211a71ae0a796eb1c3a6ea091dc6e14 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 13 Sep 2016 12:39:39 -0400 Subject: refactor --- HTTP/RateLimit.hs | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) (limited to 'HTTP') diff --git a/HTTP/RateLimit.hs b/HTTP/RateLimit.hs index d8b3dc1..e6b0344 100644 --- a/HTTP/RateLimit.hs +++ b/HTTP/RateLimit.hs @@ -92,13 +92,43 @@ bloomMaxSize = 1000000 -- period, which is especially useful when retrieving keys that were -- split into multiple chunks. However, setting this too high lets clients -- cheaply store lots of data on a server that has been idle for a while, --- which could be an attractive way to abuse keysafe servers. +-- which could be an attractive way to abuse keysafe servers for general +-- data storage. burstSize :: Word64 burstSize = 4 -- 256 kb immediate storage -- | Rate that the bucket is filled. fillRate :: Word64 -fillRate = 2 * 60 * 1000000 -- 1 token ever other minute +fillRate = 2 * 60 * 1000000 -- 1 token every other minute + +-- This is a second level rate limiter, that limits the rate that +-- RandomSalts are generated. +-- +-- This prevents an attacker flooding requests that cause new random +-- salts to be assigned, in order to fill up the bloom table and cause +-- salts assigned to other clients to be rejected. +-- +-- Since the bloom filters hold 1 million salts, with a 1 token per second +-- fill rate, the attacker would need to send requests for over 10 hours to +-- force a bloom filter rotation, so would not impact many users. +-- +-- This also makes there be a hard upper bound on the number of requests +-- per second. In a sitation where an attacker is willing to burn as much +-- CPU as necessary to do proof of work and fill up a keysafe server, +-- this is +overallRateLimit :: RateLimiter -> IO () +overallRateLimit ratelimiter = tokenBucketWait + (randomSaltGenerationLimiter ratelimiter) + overallBurstSize + overallFillRate + +-- | This can be quite high; being able to generate a few thousand +-- RandomSalts is not useful to an attacker. +overallBurstSize :: Word64 +overallBurstSize = 1000 + +overallFillRate :: Word64 +overallFillRate = 100000 -- refill 1 token per second -- | How much data could be stored, in bytes per second, assuming all -- buckets in the rate limiter are kept drained, and all requests are @@ -162,17 +192,7 @@ assignWork :: RateLimiter -> [Bucket] -> Handler (POWGuarded a) assignWork ratelimiter bs = case mapMaybe mkProofReq bs of [] -> throwError err404 (mkreq:_) -> liftIO $ do - -- This prevents an attacker flooding requests that - -- cause new random salts to be assigned, in order - -- to fill up the bloom table and cause salts assigned - -- to other clients to be rejected. - -- Since the bloom filters hold 1 million salts, - -- the attacker would need to send requests for over 10 - -- hours to force a bloom filter rotation, so would not - -- impact many users. - tokenBucketWait (randomSaltGenerationLimiter ratelimiter) - 100 -- burst - 100000 -- refill 1 token per second + overallRateLimit ratelimiter salt <- liftIO mkRandomSalt withBloomFilter ratelimiter assignedRandomSalts -- cgit v1.2.3