Configure Rack::Attack to block misbehaving clients

This commit is contained in:
Hunter Madison 2021-05-23 19:19:14 -04:00 committed by Peter Bhat Harkins
parent 6f141ada87
commit b8d91ca3c3
3 changed files with 37 additions and 0 deletions

View File

@ -46,6 +46,7 @@ gem "ruumba" # tests views
gem "sitemap_generator" # for better search engine indexing
gem "svg-graph", require: 'SVG/Graph/TimeSeries' # for charting, note workaround in lib/time_series.rb
gem 'transaction_retry' # mitigate https://github.com/lobsters/lobsters-ansible/issues/39
gem 'rack-attack' # rate-limiting
group :test, :development do
gem 'capybara'

View File

@ -150,6 +150,8 @@ GEM
nio4r (~> 2.0)
racc (1.5.2)
rack (2.2.3)
rack-attack (6.5.0)
rack (>= 1.0, < 3)
rack-mini-profiler (2.0.4)
rack (>= 1.2.0)
rack-test (1.1.0)
@ -304,6 +306,7 @@ DEPENDENCIES
oauth
pdf-reader
puma
rack-attack
rack-mini-profiler
rails (~> 6.0.3.3)
rb-readline

View File

@ -0,0 +1,33 @@
Rack::Attack.safelist('localhost') do |req|
'127.0.0.1' == req.ip || '::1' == req.ip
end
# this will kick in way too early if serving assets via rack
Rack::Attack.throttle("5 requests per second", limit: 5, period: 1, &:ip)
# we ask scrapers to sleep 1s between hits
Rack::Attack.throttle("60 requests per minute", limit: 60, period: 60, &:ip)
# there's an attacker enumeratng usernames via Tor
Rack::Attack.throttle("user enumerator", limit: 30, period: 300) do |request|
request.ip if request.path.startswith? '/u/'
end
# at some point they'll proceed to testing credentials
Rack::Attack.throttle("login", limit: 4, period: 60) do |request|
request.ip if request.post? && request.path == '/login'
end
# explain the throttle
Rack::Attack.throttled_response_retry_after_header = true
Rack::Attack.throttled_response = lambda do |env|
match_data = env['rack.attack.match_data']
now = match_data[:epoch_time]
headers = {
'RateLimit-Limit' => match_data[:limit].to_s,
'RateLimit-Remaining' => '0',
'RateLimit-Reset' => (now + (match_data[:period] - now % match_data[:period])).to_s,
}
[429, headers, ["Throttled, sleep(1) between hits; more in config/initializers/rack_attack.rb\n"]]
end