Skip to content

Commit

Permalink
Merge pull request #1349 from rubymonsters/1346-use-rack-attack
Browse files Browse the repository at this point in the history
Install rack attack with basic configuration
  • Loading branch information
zaziemo authored Feb 6, 2024
2 parents de99fa8 + ce68f96 commit ceb1651
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 0 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ gem 'rack-timeout'
gem 'pg_search'

gem 'crawler_detect'
gem 'rack-attack'

# downgrade gem to solve parsing error https://stackoverflow.com/questions/74725359/ruby-on-rails-legacy-application-update-generates-gem-psych-alias-error-psychb
gem 'psych', '< 4.0'
Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,8 @@ GEM
qonfig (0.28.0)
racc (1.7.1)
rack (2.2.6.4)
rack-attack (6.7.0)
rack (>= 1.0, < 4)
rack-piwik (0.3.0)
rack-test (2.1.0)
rack (>= 1.3)
Expand Down Expand Up @@ -512,6 +514,7 @@ DEPENDENCIES
poltergeist (= 1.18.1)
pry
psych (< 4.0)
rack-attack
rack-piwik (~> 0.3.0)
rack-timeout
rails (= 6.1.7.6)
Expand Down
78 changes: 78 additions & 0 deletions config/initializers/rack_attack.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
class Rack::Attack

### Configure Cache ###

# If you don't want to use Rails.cache (Rack::Attack's default), then
# configure it here.
#
# Note: The store is only used for throttling (not blocklisting and
# safelisting). It must implement .increment and .write like
# ActiveSupport::Cache::Store

# Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new

### Throttle Spammy Clients ###

# If any single client IP is making tons of requests, then they're
# probably malicious or a poorly-configured scraper. Either way, they
# don't deserve to hog all of the app server's CPU. Cut them off!
#
# Note: If you're serving assets through rack, those requests may be
# counted by rack-attack and this throttle may be activated too
# quickly. If so, enable the condition to exclude them from tracking.

# Throttle all requests by IP (60rpm)
#
# Key: "rack::attack:#{Time.now.to_i/:period}:req/ip:#{req.ip}"
throttle('req/ip', limit: 300, period: 3.minutes) do |req|
req.ip # unless req.path.start_with?('/assets')
end

### Prevent Brute-Force Login Attacks ###

# The most common brute-force login attack is a brute-force password
# attack where an attacker simply tries a large number of emails and
# passwords to see if any credentials match.
#
# Another common method of attack is to use a swarm of computers with
# different IPs to try brute-forcing a password for a specific account.

# 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:#{normalized_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?
# Normalize the email, using the same logic as your authentication process, to
# protect against rate limit bypasses. Return the normalized email if present, nil otherwise.
req.params['email'].to_s.downcase.gsub(/\s+/, "").presence
end
end

### Custom Throttle Response ###

# By default, Rack::Attack returns an HTTP 429 for throttled responses,
# which is just fine.
#
# If you want to return 503 so that the attacker might be fooled into
# believing that they've successfully broken your app (or you just want to
# customize the response), then uncomment these lines.
# self.throttled_response = lambda do |env|
# [ 503, # status
# {}, # headers
# ['']] # body
# end
end
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
require File.expand_path('../config/environment', __dir__)
require 'rspec/rails'
require 'capybara/poltergeist'
Rack::Attack.enabled = false
Capybara.javascript_driver = :poltergeist
Capybara.default_max_wait_time = 10
# Requires supporting ruby files with custom matchers and macros, etc,
Expand Down

0 comments on commit ceb1651

Please sign in to comment.