diff options
author | Joey Hess <joeyh@joeyh.name> | 2016-09-13 00:33:24 -0400 |
---|---|---|
committer | Joey Hess <joeyh@joeyh.name> | 2016-09-13 00:33:24 -0400 |
commit | 585ac0d24196359be0169c5f49d4e32407dc7e9f (patch) | |
tree | 5a3e602e0c7ce1a21b44df1d91c9202716f82092 /HTTP | |
parent | 48d3b7ec2576c2b0c07af10fc0c53a08a866a982 (diff) | |
download | keysafe-585ac0d24196359be0169c5f49d4e32407dc7e9f.tar.gz |
use token bucket as the random salt generation rate limiter
This avoids a 1s delay in requests, except when an attacker is flooding
them.
Diffstat (limited to 'HTTP')
-rw-r--r-- | HTTP/RateLimit.hs | 20 |
1 files changed, 9 insertions, 11 deletions
diff --git a/HTTP/RateLimit.hs b/HTTP/RateLimit.hs index 737f7dc..81e3ed2 100644 --- a/HTTP/RateLimit.hs +++ b/HTTP/RateLimit.hs @@ -9,7 +9,6 @@ import Types.Cost import HTTP import HTTP.ProofOfWork import Servant -import Control.Concurrent import Control.Concurrent.STM import Control.Concurrent.TokenBucket import qualified Data.BloomFilter.Mutable as BloomFilter @@ -34,7 +33,7 @@ data RateLimiter = RateLimiter , usedRandomSalts :: BloomFilter , usedRandomSaltsOld :: BloomFilter , numRandomSalts :: TMVar Int - , accessLock :: TMVar () + , randomSaltGenerationLimiter :: TokenBucket } type BloomFilter = TMVar (BloomFilter.MBloom RealWorld RandomSalt) @@ -54,7 +53,7 @@ newRateLimiter = RateLimiter <*> mkBloomFilter <*> mkBloomFilter <*> newTMVarIO 0 - <*> newTMVarIO () + <*> newTokenBucket where -- The last bucket takes half of maxProofOfWork to access, and -- each earlier bucket halves that time, down to the first bucket, @@ -152,18 +151,17 @@ assignWork :: RateLimiter -> [Bucket] -> Handler (POWGuarded a) assignWork ratelimiter bs = case mapMaybe mkProofReq bs of [] -> throwError err404 (mkreq:_) -> liftIO $ do - -- 10 second pause here, with a lock held so that only - -- this thread can run. 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. + -- 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. - atomically $ takeTMVar (accessLock ratelimiter) - threadDelay 10000000 - atomically $ putTMVar (accessLock ratelimiter) () + tokenBucketWait (randomSaltGenerationLimiter ratelimiter) + 100 -- burst + 100000 -- refill 1 token per second salt <- liftIO mkRandomSalt withBloomFilter ratelimiter assignedRandomSalts |