@gy-ban
2016-12-25T11:33:48.000000Z
字数 2199
阅读 1042
rails
Rack::Attack是rails用来防御一些恶意请求的rack 中间件。主要通过safelisting, blocklisting, throttling, and tracking 这几个模块来过滤每个请求。
1、安装rack-attack gem,或者将其添加到Gemfile中
gem 'rack-attack'
2、添加到application.rb
# In config/application.rb
config.middleware.use Rack::Attack
3、创建配置文件rack-attack.rb放到config/initializers/
# In config/initializers/rack-attack.rb
class Rack::Attack
# your custom configuration...
end
Rack::Attack中间件会对每一个请求进行匹配过滤,默认每个模块的值是空,所以只有在配置文件中定义了才会起到作用。
匹配顺序:
1、首先匹配safelist模块,如果匹配上则通过,不再进行后面的模块匹配。
2、如果没有,则匹配blocklist,如果匹配,就会对这个请求进行block操作
3、如果没有,则匹配throttle,这个模块会用到rails缓存用来计数,没匹配一次计数加一,一旦请求达到限定值,则进行block操作。
4、如果没有,则匹配tracks
5、如果都没有匹配上,这个请求默认是allowed
Safelists
# 允许来些本机的请求
# 如果用户在whitelist中, blacklist 与 throttles 规则将被跳过
Rack::Attack.safelist('allow from localhost') do |req|
# 如果返回 true,表示请求是允许的
'127.0.0.1' == req.ip
end
Blocklists
# 禁止来自IP 1.2.3.4的 请求
Rack::Attack.blacklist('block 1.2.3.4.') do |req|
'1.2.3.4' == req.ip
end
Fail2Ban
Rack::Attack.blacklist('fail2ban') do |req|
# 遇到匹配的请求,会直接 black (返回true)
# 如果用户继续请求,在 findtime 时间内请求超过 maxretry 次时
# 在 bantime 时间内将被禁止任何访问 (不再运行 block 中的判断,直接返回true)
Rack::Attack::Fail2Ban.filter(req.ip, maxretry: 3, findtime: 10.minutes, bantime: 5.minutes) do
req.params['query'] =~ /password|admin/
end
end
Allow2Ban
Rack::Attack.blacklist('allow2ban login scrapers') do |req|
# 遇到匹配的请求会返回 false
# 如果用户在 findtime 时间内请求超过 maxretry 次时
# 在 bantime 时间内将被禁止任何访问 (不再运行 block 中的判断,直接返回true)
Rack::Attack::Allow2Ban.filter(req.ip, maxretry: 10, findtime: 1.minute, bantime: 1.hour) do
req.path == '/login'
end
end
Throttles
# 限制每个 IP 每秒(period) 最多发送 3 个请求
Rack::Attack.throttle('req/ip', limit: 3, period: 1.second) do |req|
req.ip
end
# 限制每个 email 60秒内,最多请求 `/login` 接口5次
Rack::Attack.throttle('login/email', limit: 5, period: 60) do |req|
if req.path == '/login' && req.post?
req.params['email']
end
end
# 通过proc来动态调整 limit 和 period
limit_proc = proc {|req| req.env["REMOTE_USER"] == "admin" ? 100 : 1}
period_proc = proc {|req| req.env["REMOTE_USER"] == "admin" ? 1.second : 1.minute}
Rack::Attack.throttle('req/ip', :limit => limit_proc, :period => period_proc) do |req|
req.ip
end
Tracks
# 追踪特定的请求,每个匹配的请求都会触发 notification
Rack::Attack.trace('special_agent') do |req|
req.user_agent == 'SpecialAgent'
end
# 支持可选参数 limit 和 period, 只有达到 limit 的限制时,才会触发 notification
Rack::Attack.trace('special_agent', limit: 10, period: 1.minute) do |req|
req.user_agent == 'SpecialAgent'
end