Rails框架下应对机器人恶意请求的最优方案咨询——关于重定向方案安全性及日志优化的疑问
应对Rails应用遭恶意请求轰炸的解决方案探讨
最近我们的Rails应用被大量随机POST和GET请求轰炸,POST请求大多因为无效的authenticity token返回500/422错误,典型日志如下:
Started POST "/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php" for 45.146.165.123 at 2021-06-29 04:15:39 -0400 I, [2021-06-29T04:15:39.769996 #2050] INFO -- : [be4241b9-0494-4fb5-b434-2d11038017f1] Processing by HomeController#index as I, [2021-06-29T04:15:39.770109 #2050] INFO -- : [be4241b9-0494-4fb5-b434-2d11038017f1] Parameters: {"<?"=>"md5(\"phpunit\")?>", "path"=>"vendor/phpunit/phpunit/src/Util/PHP/eval-stdin"} W, [2021-06-29T04:15:39.790171 #2050] WARN -- : [be4241b9-0494-4fb5-b434-2d11038017f1] Can't verify CSRF token authenticity. I, [2021-06-29T04:15:39.833066 #2050] INFO -- : [be4241b9-0494-4fb5-b434-2d11038017f1] Completed 422 Unprocessable Entity in 53ms (MongoDB: 0.0ms) F, [2021-06-29T04:15:39.916526 #2050] FATAL -- : [be4241b9-0494-4fb5-b434-2d11038017f1] F, [2021-06-29T04:15:39.916666 #2050] FATAL -- : [be4241b9-0494-4fb5-b434-2d11038017f1] ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
我们原本考虑采用「Intermittent Rails 5 ActionController::InvalidAuthenticityToken」方案,但担心机器人会察觉到我们的重定向操作,想问问这种做法有没有风险?有没有更好的方案既能拦截这些机器人,又能避免生产日志被大量错误信息淹没?
先说说「Intermittent InvalidAuthenticityToken」方案的风险
这个方案的核心是间歇性返回重定向而非直接抛出错误,确实存在不小的隐患:
- 机器人可以通过检测3xx状态码识别出自己被针对性拦截,进而调整攻击策略——比如更换IP池、调整请求频率、伪装请求头,甚至转向其他潜在漏洞尝试。
- 如果重定向逻辑设计得不够严谨,还可能被利用来进行SSRF(服务器端请求伪造)或者重定向钓鱼攻击(不过后者在你的场景下概率较低)。
更优的拦截&日志优化方案
我建议从基础设施层、应用层、日志层三个维度入手,既能有效拦截恶意请求,又能减少日志污染:
1. 基础设施层拦截(最高效,直接把请求挡在应用外)
- CDN/WAF规则:用Cloudflare、AWS WAF这类服务,直接拦截带有明显攻击特征的请求:
- 拦截路径包含
phpunit、eval-stdin.php这类常见攻击路径的请求,直接返回403 Forbidden; - 设置速率限制,对单一IP的请求频率做阈值限制(比如每分钟最多100次),超过就临时封禁10-15分钟。
- 拦截路径包含
- Web服务器配置:在Nginx/Apache层面添加规则,过滤带有恶意参数(比如
<?这种PHP注入特征)的请求,或者拦截无User-Agent、带有攻击工具标识的UA请求。
2. Rails应用层优化(补充防护+减少日志污染)
- 自定义InvalidAuthenticityToken处理逻辑:不要让框架直接抛出500错误,而是静默返回403,并且不记录冗余的错误日志。你可以在
ApplicationController里重写handle_unverified_request方法:
这样既避免了生产日志被大量错误淹没,也不会给机器人明确的拦截信号(统一返回403,和正常的权限拒绝状态一致)。def handle_unverified_request # 针对恶意请求,直接返回403,不触发完整的错误栈日志 head :forbidden, content_type: 'text/plain' end - 集成Rack::Attack做应用层防护:这个中间件可以帮你做速率限制、IP封禁:
# 先在Gemfile添加 gem 'rack-attack' # 然后在config/initializers/rack_attack.rb里配置 class Rack::Attack # 限制单一IP每分钟最多100次非静态资源请求 throttle('req/ip', limit: 100, period: 1.minute) do |req| req.ip unless req.path.start_with?('/assets', '/packs') end # 直接封禁请求恶意路径的IP blocklist('malicious_paths') do |req| req.path.include?('/vendor/phpunit') || req.path.include?('eval-stdin.php') end end - CSRF验证增强:对于敏感接口,可以额外检查
X-Requested-With请求头是否为XMLHttpRequest(针对AJAX请求),或者添加自定义的请求头验证规则。
3. 日志层优化
- 日志分割与过滤:用Logrotate把正常访问日志和错误日志分开,同时在Rails配置里,将
ActionController::InvalidAuthenticityToken这类错误的日志级别调低,或者只记录到专门的攻击日志文件中,不要污染主生产日志。 - 精简错误日志:修改Rails的日志配置,避免记录这类恶意请求的完整栈信息,只保留关键的IP、请求路径、时间戳即可。
总的来说,优先用基础设施层的拦截方案,能最大程度减少应用层的压力;应用层做补充防护和日志优化;尽量保持返回状态码的一致性(比如统一返回403),让机器人难以判断自己是否被识别,避免触发他们的自适应攻击策略。
内容的提问来源于stack exchange,提问作者user1130176
相关产品推荐
相关产品推荐

