Skip to content

Commit

Permalink
Fix for bug #3214 which had noted there was no request rate limit to
Browse files Browse the repository at this point in the history
resetting the password.

The Rack-Attack middleware for blocking & throttling abusive requests is
being used.
https://github.com/rack/rack-attack/blob/6-stable/README.md

Changes:
- Added rack-attack version 6.6.1 gem. https://rubygems.org/gems/rack-attack/versions/6.6.1
- Added config/initializers/rack_attack.rb:
  - The rack-attack functionality is enabled with
        Rack::Attack.enabled = true
    but may be switched off
        Rack::Attack.enabled = false.
  - Password reset requests are currently throttled from from an IP address
    for POSTs to path /users/passwords and is limited 2 requests every 30 seconds.
ess
  - Login requests are throttled  from an IP address
    for POSTs to path /users/sign_in and is limited 4 requests every 30 seconds.  - A new html page public/429.html with title "Too Many Request" is added.
  • Loading branch information
John Pinto committed Dec 19, 2022
1 parent a803f43 commit 94ef895
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 0 deletions.
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ gem 'jwt'
# OO authorization for Rails (https://github.com/elabs/pundit)
gem 'pundit'

# Gem for throttling malicious attacks
gem 'rack-attack', '~> 6.6', '>= 6.6.1'

# ========== #
# UI / VIEWS #
# ========== #
Expand Down
25 changes: 25 additions & 0 deletions config/initializers/rack_attack.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true

# NB: `req` is a Rack::Request object (basically an env hash with friendly accessor methods)

# Enable/disable Rack::Attack
Rack::Attack.enabled = true

# Cache store required to work.
Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new # defaults to Rails.cache

# Throttle should send a 429 Error responsec code and display public/429.html
Rack::Attack.throttled_responder = lambda do |env|
html = ActionView::Base.empty.render(file: 'public/429.html')
[429, {'Content-Type' => 'text/html'}, [html]]
end

# Throttle attempts to a particular path. 2 POSTs to /users/password every 30 seconds
Rack::Attack.throttle "password_resets/ip", limit: 2, period: 30.seconds do |req|
req.post? && req.path == "/users/password" && req.ip
end

# Throttle attempts to a particular path. 4 POSTs to /users/sign_in every 30 seconds
Rack::Attack.throttle "logins/ip", limit: 4, period: 30.seconds do |req|
req.post? && req.path == "/users/sign_in" && req.ip
end
29 changes: 29 additions & 0 deletions public/429.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<title>We're sorry, but something went wrong (500)</title>
<style type="text/css">
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
div.dialog {
width: 25em;
padding: 0 4em;
margin: 4em auto 0 auto;
border: 1px solid #ccc;
border-right-color: #999;
border-bottom-color: #999;
}
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
</style>
</head>

<body>
<!-- This file lives in public/429.html -->
<div class="dialog">
<h1>Too Many Requests</h1>

<p>You have exceeded the number of requests for this resource. For security reasons access is limited to a fixed number in a given period. Retry later.</p>


</div>
</body>
</html>

0 comments on commit 94ef895

Please sign in to comment.