WEB安全中除典型攻击外(如SQL注入、文件上传、敏感文件泄漏等),近些年来CC攻击也逐渐走向”正轨”,占有相当比例。结合业务场景,我们也使用ngx_lua实现了CDN waf防护系统,本文主要分享传统Nginx防CC的一些经验,以及自建CDN waf防护系统中基础模块的实现。 早期线上做CC防护,通常是限制IP访问、同一IP请求数、并发数来实现,主要模块有: 通常结合Core模块limite_rate做限速、map模块做变量映射、Geo模块做白名单策略等等。 具体Nginx模块的详细简介以及安装过程,则不再赘述,有兴趣的看客可以直接查看官方文档。 http://nginx.org/en/docs/ 2.1 IP访问限制 针对IP做访问限制,一般可使用allow/deny指令,即http_access_module模块,默认自带(除非编译显式指明--without-http_access_module)。被deny拦截的请求返回403。 参考实例:
经验: (1) 规则匹配自上而下、精细规则要靠前写、不要漏写默认规则; (2) 通常将allow、deny条目写成规则文件如blockip.conf ,通过 include blockip.conf引入, 可在http、server、location及limit_except配置段中引入; (3) 更改规则需重载nginx生效,由于无法预知攻击者IP,并不适合动态防CC。适合针对特定站点/路径 做访问保护,如CDN健康状态页只允许本机、中央机访问。 2.2请求数限制 ngx_http_limit_req_module模块可通过预先定义的键值来限制请求处理的频率,默认自带(除非编译显式指明--without-http_limit_req_module)。如果定义客户端IP为键值,则可以针对同一IP单位时间内的请求数做限制(无论这些请求是否处理),是”请求数量层面限制”。 限流原理是” leaky bucket”(漏桶算法):服务器以恒定的速率处理请求,超出处理速率的请求放在burst队列中延迟处理,严重超出的请求(大于恒定处理速率 burst队列上限)则直接丢弃。 参考示例:针对动态页面做请求限制
配置说明: (1) 定义$binary_remote_addr为KEY,即客户端IP作为"请求标识"(用于计数); (2) zone=req_limit:20m 生成大小20m、名为dynamic_req_limit的内存区域, 用于存储访问频次信息; (3) rate=20r/s 表示相同"请求标识"(即IP相同)的请求、每秒处理20个; (4) zone=dynamic_req_limit burst=100在location配置段下,是指针对动态请求(aspx|jsp|php)限制同一IP每秒最多处理20次请求,burst为缓冲队列,超出20小于120的请求可进入队列延迟处理,超出120以上的请求会被丢弃并默认返回503; (5) limit_req_log_level error 用于记录日志0.8.18 版本支持; (6) limit_req_status 403 被拒绝的请求(即超出rate burst总上限)默认返回503,在1.3.15 版本后支持自定义状态码,这里修改为403。 经验: (1) 1.7.6 版本前,KEY只能是单个变量;更高版本KEY支持多个变量、文本等组合,CDN场景下通常是将”IP 访问URI”作为唯一标识,来做策略限制,如:
(2) limit_req 指令可配置nodelay参数,若未设置nodelay,则当前时刻处于burst队列的请求需到下一秒执行;设置nodelay会强制将当前burst队列请求也同一时刻处理(增大瞬间吞吐),即此刻请求要么被处理、要么被丢弃,burst队列为空;
(3) $binary_remote_addr为固定4字节,相比$remote_addr(7~15字节)节约内存;状态位(即频次信息)32位平台占用64字节,64位平台占用128字节,因此64位平台上,1M zone可保存约8000个IP状态。具体zone大小可根据key值大小、rate限制频率及Web服务QPS来推算; (4) $binary_remote_addr仅代表TCP连接的对端IP地址,在前端有代理转发、负载均衡器、CDN场景等情况下,该值不能作为req_limit key(并非用户真实IP),比如通过HTTP header提取用户真实IP,参考如下 |
|
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|