rails_api_base icon indicating copy to clipboard operation
rails_api_base copied to clipboard

Add rack attack for login endpoint

Open martinjaimem opened this issue 5 years ago • 3 comments

For security reasons, I think it makes sense to have the login endpoint limited.

For example something like this:

RACK_ATTACK_THROTTLE_LIMIT = ENV.fetch('RACK_ATTACK_THROTTLE_LIMIT', 6)
RACK_ATTACK_THROTTLE_PERIOD_IN_SECONDS = ENV.fetch('RACK_ATTACK_THROTTLE_PERIOD', 1.minute.to_i)

Rack::Attack.throttle(
  'requests_to_api_login_path_per_minute_per_ip',
  limit: RACK_ATTACK_THROTTLE_LIMIT,
  period: RACK_ATTACK_THROTTLE_PERIOD_IN_SECONDS
) do |request|
  login_path = Rails.application.routes.url_helpers.new_user_session_path
  request.ip if request.path.starts_with?(login_path)
end

martinjaimem avatar Oct 23 '20 12:10 martinjaimem

Why not add this to the whole API?

Related: https://blog.heroku.com/rate-throttle-api-client

juanmanuelramallo avatar Oct 23 '20 13:10 juanmanuelramallo

Not only the login end but also a default config to block malicious ips https://github.com/rack/rack-attack/blob/master/docs/example_configuration.md

  # 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: 5.minutes) do |req|
    req.ip # unless req.path.start_with?('/assets')
  end```

vitogit avatar Oct 23 '20 13:10 vitogit

I agree with @vitogit and you may also consider throttle for user emails:

# Throttle login attempts for a given email parameter to 6 reqs/minute
# Return the *normalized* email as a discriminator on POST /login requests
Rack::Attack.throttle('limit logins per email', limit: 6, period: 60) 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.
    req.params['email'].to_s.downcase.gsub(/\s+/, "")
  end
end

This is useful to be protected against malicious users trying to log in for another user email (with different ips)

BelenRemedi avatar Oct 23 '20 13:10 BelenRemedi