Skip to content

Commit b624220

Browse files
authored
Configs Rack:Attack (#311)
* Configs Rack:Attack * Resolves conflits from specs on Rack:Attack configs
1 parent a960390 commit b624220

File tree

4 files changed

+93
-1
lines changed

4 files changed

+93
-1
lines changed

Gemfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ gem "administrate", "0.20.1"
1414
# Reduces boot times through caching; required in config/boot.rb
1515
gem "bootsnap", "1.18.3", require: false
1616

17+
# Rack middleware for blocking & throttling
18+
gem 'rack-attack'
19+
1720
# Use Sass to process CSS
1821
# gem "sassc-rails"
1922
# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]

Gemfile.lock

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,8 @@ GEM
373373
rspec-support (~> 3.12)
374374
racc (1.8.0)
375375
rack (3.1.4)
376+
rack-attack (6.7.0)
377+
rack (>= 1.0, < 4)
376378
rack-cors (2.0.2)
377379
rack (>= 2.0.0)
378380
rack-protection (4.0.0)
@@ -562,7 +564,7 @@ GEM
562564
tzinfo (2.0.6)
563565
concurrent-ruby (~> 1.0)
564566
unicode-display_width (2.5.0)
565-
uri (0.13.0)
567+
uri (0.13.2)
566568
version_gem (1.1.4)
567569
warden (1.2.9)
568570
rack (>= 2.0.9)
@@ -617,6 +619,7 @@ DEPENDENCIES
617619
puma (= 6.4.2)
618620
pundit (= 2.3.2)
619621
pundit-matchers (~> 4.0)
622+
rack-attack
620623
rack-cors (= 2.0.2)
621624
rails (= 7.1.3.4)
622625
redis (= 5.2.0)

config/initializers/rack_attack.rb

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# frozen_string_literal: true
2+
3+
class Rack::Attack
4+
5+
### Configure Cache ###
6+
7+
# If you don't want to use Rails.cache (Rack::Attack's default), then
8+
# configure it here.
9+
#
10+
# Note: The store is only used for throttling (not blocklisting and
11+
# safelisting). It must implement .increment and .write like
12+
# ActiveSupport::Cache::Store
13+
14+
Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
15+
16+
### Throttle Spammy Clients ###
17+
18+
# If any single client IP is making tons of requests, then they're
19+
# probably malicious or a poorly-configured scraper. Either way, they
20+
# don't deserve to hog all of the app server's CPU. Cut them off!
21+
#
22+
# Note: If you're serving assets through rack, those requests may be
23+
# counted by rack-attack and this throttle may be activated too
24+
# quickly. If so, enable the condition to exclude them from tracking.
25+
26+
# Throttle all requests by IP (60rpm)
27+
#
28+
# Key: "rack::attack:#{Time.now.to_i/:period}:req/ip:#{req.ip}"
29+
throttle('req/ip', limit: 300, period: 5.minutes) do |req|
30+
req.ip # unless req.path.start_with?('/assets')
31+
end
32+
33+
### Prevent Brute-Force Login Attacks ###
34+
35+
# The most common brute-force login attack is a brute-force password
36+
# attack where an attacker simply tries a large number of emails and
37+
# passwords to see if any credentials match.
38+
#
39+
# Another common method of attack is to use a swarm of computers with
40+
# different IPs to try brute-forcing a password for a specific account.
41+
42+
# Throttle POST requests to /login by IP address
43+
#
44+
# Key: "rack::attack:#{Time.now.to_i/:period}:logins/ip:#{req.ip}"
45+
throttle('logins/ip', limit: 5, period: 20.seconds) do |req|
46+
if req.path == '/login' && req.post?
47+
req.ip
48+
end
49+
end
50+
51+
# Throttle POST requests to /login by email param
52+
#
53+
# Key: "rack::attack:#{Time.now.to_i/:period}:logins/email:#{normalized_email}"
54+
#
55+
# Note: This creates a problem where a malicious user could intentionally
56+
# throttle logins for another user and force their login requests to be
57+
# denied, but that's not very common and shouldn't happen to you. (Knock
58+
# on wood!)
59+
throttle('logins/email', limit: 5, period: 20.seconds) do |req|
60+
if req.path == '/login' && req.post?
61+
# Normalize the email, using the same logic as your authentication process, to
62+
# protect against rate limit bypasses. Return the normalized email if present, nil otherwise.
63+
req.params['email'].to_s.downcase.gsub(/\s+/, "").presence
64+
end
65+
end
66+
67+
### Custom Throttle Response ###
68+
69+
# By default, Rack::Attack returns an HTTP 429 for throttled responses,
70+
# which is just fine.
71+
#
72+
# If you want to return 503 so that the attacker might be fooled into
73+
# believing that they've successfully broken your app (or you just want to
74+
# customize the response), then uncomment these lines.
75+
# self.throttled_responder = lambda do |env|
76+
# [ 503, # status
77+
# {}, # headers
78+
# ['']] # body
79+
# end
80+
end
81+

spec/rails_helper.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,9 @@
7373
# arbitrary gems may also be filtered via:
7474
# config.filter_gems_from_backtrace("gem name")
7575
Rails.root.glob("spec/support/**/*.rb").each { |f| require f }
76+
77+
# Clears Rack:Attack cache between specs
78+
config.before(:each) do
79+
Rack::Attack.cache.store.clear if Rack::Attack.cache.store.respond_to?(:clear)
80+
end
7681
end

0 commit comments

Comments
 (0)