很抱歉延迟回复您;我花了一段时间来挖掘与此相关的旧代码。
正如上面评论中所讨论的,这里是一个使用 a 的解决blacklist
方案findtime
# config/initilizers/rack-attack.rb
class Rack::Attack
(1..6).each do |level|
blocklist("allow2ban login scrapers - level #{level}") do |req|
Allow2Ban.filter(
req.ip,
maxretry: (20 * level),
findtime: (8**level).seconds,
bantime: (8**level).seconds
) do
req.path == '/users/sign_in' && req.post?
end
end
end
end
您可能希望根据您的特定应用程序调整这些数字;上面的数字只是我认为对我的特定应用程序“合理”的数字——它们并非来自任何官方标准。
使用上述方法的一个问题是,在开发/测试(例如您的rspec
测试套件)应用程序时,您可以轻松地达到上述限制并无意中限制自己。这可以通过将以下配置添加到初始化程序来避免:
safelist('allow from localhost') do |req|
'127.0.0.1' == req.ip || '::1' == req.ip
end
最常见的暴力登录攻击是暴力密码攻击,攻击者只需尝试大量电子邮件和密码以查看是否有任何凭据匹配。
在几次失败的登录尝试后,您应该在应用程序中使用帐户 LOCK 来缓解这种情况。(例如,如果使用,devise
则有一个内置Lockable
模块可供您使用。)
然而,这种帐户锁定方法打开了一个新的攻击向量:攻击者可以通过登录尝试向系统发送垃圾邮件,使用有效的电子邮件和错误的密码,不断重新锁定所有帐户!
此配置通过以指数方式限制来自给定 IP 的登录尝试次数,有助于缓解该攻击向量。
我还添加了以下“包罗万象”的请求限制:
throttle('req/ip', limit: 300, period: 5.minutes, &:ip)
这主要是为了限制恶意/配置不当的爬虫;以防止它们占用所有应用服务器的 CPU。
注意:如果您通过机架服务资产,这些请求可能会被机架攻击计数,并且此限制可能被激活得太快。如果是这样,请启用条件以将它们排除在跟踪之外。
我还编写了一个集成测试以确保我的Rack::Attack
配置正常工作。让这个测试工作有一些挑战,所以我会让代码+注释自己说话:
class Rack::AttackTest < ActionDispatch::IntegrationTest
setup do
# Prevent subtle timing issues (==> intermittant test failures)
# when the HTTP requests span across multiple seconds
# by FREEZING TIME(!!) for the duration of the test
travel_to(Time.now)
@removed_safelist = Rack::Attack.safelists.delete('allow from localhost')
# Clear the Rack::Attack cache, to prevent test failure when
# running multiple times in quick succession.
#
# First, un-ban localhost, in case it is already banned after a previous test:
(1..6).each do |level|
Rack::Attack::Allow2Ban.reset('127.0.0.1', findtime: (8**level).seconds)
end
# Then, clear the 300-request rate limiter cache:
Rack::Attack.cache.delete("#{Time.now.to_i / 5.minutes}:req/ip:127.0.0.1")
end
teardown do
travel_back # Un-freeze time
Rack::Attack.safelists['allow from localhost'] = @removed_safelist
end
test 'should block access on 20th successive /users/sign_in attempt' do
19.times do |i|
post user_session_url
assert_response :success, "was not even allowed to TRY to login on attempt number #{i + 1}"
end
# For DOS protection: Don't even let the user TRY to login; they're going way too fast.
# Rack::Attack returns 403 for blocklists by default, but this can be reconfigured:
# https://github.com/kickstarter/rack-attack/blob/master/README.md#responses
post user_session_url
assert_response :forbidden, 'login access should be blocked upon 20 successive attempts'
end
end