最近公司最近的几台线上服务器常常出现CPU覆盖太高,影响部分应用响应超时,产生了大量的短信和邮件报警,通过排查数据库日志和access.log,发现是API接口被刷,被恶意疯狂请求,最大一次大概120次/s。php
以前没有过太多这方面经验,处理起来不是很顺畅,此次的问题恰好提了醒,通过此次的问题暴露,来记录一下解决方案和策略。nginx
线上的部署方案是:nginx + laravel。laravel
首先咱们尝试从nginx层面入手,将占用更少的内存消耗,无需再转发到php-fpm上处理。算法
想好很好的特征,就必须捕捉必定的特征,经过这个特征来有效的控制到恶意请求。数据库
首先的话.就是控制单IP时间上的请求次数和IP链接数,配置以下:api
http { limit_req_zone $binary_remote_addr zone=one:1m rate=1r/s; server { location /api/ { limit_req zone=one burst=5; } } }
limit_req_zone主要控制单个IP的请求速率,使用漏桶算法来完成限制,limit_req_zone size,主要用于储存统计IP的请求信息,1M能够储存16000个IP,当每秒的请求超过了16000个的时候,其他访问都会被访问503 服务暂不可用。服务器
上面的模板设置了,每秒最大不超过1个请求,最大延迟请求不超过5个。并发
若是咱们的服务器每次接口的响应时间是在200ms-300ms,那咱们对应的每秒的限制就应该设置成 1000ms / 接口响应耗时
。curl
限制完用户请求频率后,若是仍然仍是存在很大的恶意请求,咱们还能够进行并发数的限制。php-fpm
http { limit_conn_zone $binary_remote_addr zone=one:1m; server { location /api/ { limit_conn one 10; } } }
limit_conn_zone:主要是用于控制请求并发数,频率不能太快。
limit_conn_zone size跟limit_req_zone意思一致,可根据须要动态调控,上面的案例中,表示限制每一个客户端IP最大并发链接数为10。
当某个IP请求过于频繁或者须要彻底杜绝该IP的访问时,能够经过nginx的deny配置来禁止黑名单中的IP访问。
http { include blockip.conf; }
黑名单配置
deny 195.91.112.66; deny 192.168.2.100;
被添加黑名单后,再次访问就会出现403禁止访问.
http { server { if ($http_user_agent ~* "curl") { return 403; } } }
上面就禁止了ua信息为curl的客户端,直接返回403。
禁止多个ua,经过|来隔断。
if ($http_user_agent ~* "curl|wget") { return 403; }
在咱们的laravel项目中,存在一个Throttle中间件,该策略,能够在应用层上面,有效抑制用户能够恶意请求,配置以下:
Route::group(['middleware' => 'throttle:30:1'],function(){ Route::any('/login', 'LoginController@login'); });
在throttle配置中,第一个参数控制了请求数,第二个参数用于控制请求频率,上面的配置代表,每一个客户端IP每分钟最大请求30次 login
路由。
当客户端ip超出请求限制后,服务端就会返回429 Too Many Attempts.
响应