add rate limiting headers
This commit is contained in:
parent
959aa693f3
commit
eed5ff76ef
1 changed files with 54 additions and 10 deletions
|
@ -1,15 +1,59 @@
|
||||||
class Rack::Attack
|
class Rack::Attack
|
||||||
end
|
Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
|
||||||
|
|
||||||
Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
|
# Throttle all requests by IP (60rpm)
|
||||||
|
|
||||||
# Throttle requests to 5 requests per second per ip
|
|
||||||
Rack::Attack.throttle('load_url_title/req/ip', :limit => 5, :period => 1.second) do |req|
|
|
||||||
# If the return value is truthy, the cache key for the return value
|
|
||||||
# is incremented and compared with the limit. In this case:
|
|
||||||
# "rack::attack:#{Time.now.to_i/1.second}:load_url_title/req/ip:#{req.ip}"
|
|
||||||
#
|
#
|
||||||
# If falsy, the cache key is neither incremented nor checked.
|
# Key: "rack::attack:#{Time.now.to_i/:period}:req/ip:#{req.ip}"
|
||||||
|
throttle('req/ip', :limit => 300, :period => 5.minutes) do |req|
|
||||||
|
req.ip # unless req.path.start_with?('/assets')
|
||||||
|
end
|
||||||
|
|
||||||
req.ip if req.path === 'hacks/load_url_title'
|
# Throttle POST requests to /login by IP address
|
||||||
|
#
|
||||||
|
# Key: "rack::attack:#{Time.now.to_i/:period}:logins/ip:#{req.ip}"
|
||||||
|
throttle('logins/ip', :limit => 5, :period => 20.seconds) do |req|
|
||||||
|
if req.path == '/login' && req.post?
|
||||||
|
req.ip
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Throttle POST requests to /login by email param
|
||||||
|
#
|
||||||
|
# Key: "rack::attack:#{Time.now.to_i/:period}:logins/email:#{req.email}"
|
||||||
|
#
|
||||||
|
# Note: This creates a problem where a malicious user could intentionally
|
||||||
|
# throttle logins for another user and force their login requests to be
|
||||||
|
# denied, but that's not very common and shouldn't happen to you. (Knock
|
||||||
|
# on wood!)
|
||||||
|
throttle("logins/email", :limit => 5, :period => 20.seconds) do |req|
|
||||||
|
if req.path == '/login' && req.post?
|
||||||
|
# return the email if present, nil otherwise
|
||||||
|
req.params['email'].presence
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
throttle('load_url_title/req/ip', :limit => 5, :period => 1.second) do |req|
|
||||||
|
# If the return value is truthy, the cache key for the return value
|
||||||
|
# is incremented and compared with the limit. In this case:
|
||||||
|
# "rack::attack:#{Time.now.to_i/1.second}:load_url_title/req/ip:#{req.ip}"
|
||||||
|
#
|
||||||
|
# If falsy, the cache key is neither incremented nor checked.
|
||||||
|
|
||||||
|
req.ip if req.path == 'hacks/load_url_title'
|
||||||
|
end
|
||||||
|
|
||||||
|
self.throttled_response = lambda do |env|
|
||||||
|
now = Time.now
|
||||||
|
match_data = env['rack.attack.match_data']
|
||||||
|
period = match_data[:period]
|
||||||
|
limit = match_data[:limit]
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
'X-RateLimit-Limit' => limit.to_s,
|
||||||
|
'X-RateLimit-Remaining' => '0',
|
||||||
|
'X-RateLimit-Reset' => (now + (period - now.to_i % period)).to_s
|
||||||
|
}
|
||||||
|
|
||||||
|
[429, headers, ['']]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue