gpt4 book ai didi

ruby-on-rails - 使用 Rack::Attack 防止快速登录尝试

转载 作者:太空宇宙 更新时间:2023-11-03 18:06:36 25 4
gpt4 key购买 nike

我们一直在阅读 Definitive guide to form based website authentication目的是防止快速登录尝试。

这方面的一个例子可能是:

  • 1 次尝试失败 = 没有延迟
  • 2 次失败尝试 = 2 秒延迟
  • 3 次失败尝试 = 4 秒延迟
  • 等等

其他方法出现在指南中,但它们都需要能够记录以前失败尝试的存储。

黑名单在 this issue 中的一篇帖子中进行了讨论。 (出现在文档中更改为阻止列表的旧名称黑名单下)作为可能的解决方案。

具体根据 Rack::Attack,一个简单的实现示例可能是:

登录失败的地方:

StorageMechanism.increment("bad-login/#{req.ip")

在 rack-attack.rb 中:

Rack::Attack.blacklist('bad-logins') { |req|
StorageMechanism.get("bad-login/#{req.ip}")
}

这里有两个部分,如果它被列入黑名单则返回响应并检查是否发生了先前的失败尝试(StorageMechanism)。

第一部分,返回响应,可以由 gem 自动处理。但是,我对第二部分不太清楚,至少对于 gem 和 Rails 世界缓存后端的实际选择 Redis 是这样。

据我所知,Redis 中的过期键会被自动移除。这将无法访问信息(即使已过期)、为计数器设置新值并相应地增加不应期的超时。

有什么方法可以用 Redis 和 Rack::Attack 来实现吗?

我在想,在这种情况下,“StorageMechanism”可能必须保持绝对不可知,并且对 Rack::Attack 及其存储选择一无所知。

最佳答案

很抱歉延迟回复您;我花了一些时间来挖掘与此相关的旧代码。

正如上面评论中所讨论的,这是一个使用 blacklistfindtime

的解决方案
# 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 module。)

但是,这种帐户锁定方法开启了一个新的攻击途径:攻击者可以使用有效的电子邮件和不正确的密码向系统发送垃圾邮件以尝试登录,从而不断地重新锁定所有帐户!

此配置通过指数级限制来自给定 IP 的登录尝试次数,有助于减轻该攻击向量。

我还添加了以下“包罗万象”的请求限制:

throttle('req/ip', limit: 300, period: 5.minutes, &:ip)

这主要是为了限制恶意/配置不当的爬虫;以防止它们占用应用服务器的所有 CPU。

注意:如果您通过 rack 提供 Assets ,这些请求可能会被 rack-attack 计数,并且此限制可能会激活得太快。如果是这样,启用条件以将它们排除在跟踪之外。


我还编写了一个集成测试以确保我的 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

关于ruby-on-rails - 使用 Rack::Attack 防止快速登录尝试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44018724/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com