Last active
March 5, 2019 09:36
-
-
Save ershad/b7ff20bcf8304e76e09c5834cddadff5 to your computer and use it in GitHub Desktop.
Rack::Attack sample configuration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Rack::Attack | |
# By default, Rack::Attack uses `Rails.cache` to store requests information. | |
# It's configurable as follows - | |
# | |
# redis_client = Redis.connect(url: ENV["REDIS_URL"]) | |
# Rack::Attack.cache.store = Rack::Attack::StoreProxy::RedisStoreProxy.new(redis_client) | |
class Request < ::Rack::Request | |
# You many need to specify a method to fetch the correct remote IP address | |
# if the web server is behind a load balancer. | |
def remote_ip | |
@remote_ip ||= (env['HTTP_CF_CONNECTING_IP'] || env['action_dispatch.remote_ip'] || ip).to_s | |
end | |
def allowed_ip? | |
allowed_ips = ["127.0.0.1", "::1"] | |
allowed_ips.include?(remote_ip) | |
end | |
end | |
# Throttle all requests to root path by IP (40rpm/IP) | |
throttle("req/ip", :limit => 40, :period => 1.minute) do |req| | |
req.remote_ip if req.path == "/" | |
end | |
# Exponential backoff for all requests to root path | |
# | |
# Allows 240 requests in ~8 minutes | |
# 480 requests in ~1 hour | |
# 960 requests in ~8 hours (~2,880 requests/day) | |
(3..5).each do |level| | |
throttle("req/ip/#{level}", :limit => (30 * (2 ** level)), :period => (0.9 * (8 ** level)).to_i.seconds) do |req| | |
req.remote_ip if req.path == "/" | |
end | |
end | |
# Do not throttle for allowed IPs | |
safelist('allow from localhost') do |req| | |
req.allowed_ip? | |
end | |
end | |
# Log blocked events | |
ActiveSupport::Notifications.subscribe('rack.attack') do |name, start, finish, request_id, req| | |
if req.env["rack.attack.match_type"] == :throttle | |
request_headers = { "CF-RAY" => req.env["HTTP_CF_RAY"], "X-Amzn-Trace-Id" => req.env["HTTP_X_AMZN_TRACE_ID"] } | |
Rails.logger.info "[Rack::Attack][Blocked] remote_ip: \"#{req.remote_ip}\", path: \"#{req.path}\", headers: #{request_headers.inspect}" | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment