轻量化DDoS防护的核心思路,不是用昂贵的硬件去硬抗,而是利用现有的服务器软件、协议特性和网络架构,在攻击流量到达应用瓶颈之前就将其过滤或分散。无硬件设备意味着你要把Nginx、内核参数、CDN的隐藏功能以及Anycast网络用到极致。下面直接进入具体的操作层面,不讲废话。
利用Nginx进行高效的请求过滤与速率限制Nginx是轻量化防御的第一道闸门。面对DDoS,不要依赖应用层代码,要在Web服务器层直接拒绝恶意连接。首先,调整worker进程和连接数。将worker_processes设置为auto,worker_connections根据内存调整,通常一个worker连接占用约2MB内存,你可以用ulimit -n调大系统文件描述符限制后,把worker_connections设到65535甚至更高。这能确保Nginx本身不会因为连接数耗尽而崩溃。
关键的防御手段是limit_req和limit_conn模块。limit_req针对请求速率,基于漏桶算法。针对登录页、API接口这些易被CC攻击的URL,设置一个共享内存区域来记录请求频率。例如,定义一个10MB的共享内存区,限制每IP每秒只能请求1次,突发容量为5。配置如下:
http {
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
server {
location /login {
limit_req zone=login burst=5 nodelay;
proxy_pass http://backend;
}
location /api {
limit_req zone=api burst=20 nodelay;
proxy_pass http://backend;
}
}
}
nodelay参数很关键,它让超出burst的请求立刻返回503,而不是排队等待,防止服务器资源被慢速攻击拖垮。limit_conn则限制并发连接数,针对下载类资源或全站设置,比如每个IP只能同时建立10个连接。这能有效防御一些通过维持大量空连接消耗资源的攻击。
更深层的过滤在location区块内用if指令和map模块实现。你可以根据User-Agent、Referer、请求方法进行硬拒绝。对于明显的扫描器特征,直接返回444状态码让Nginx直接关闭连接,连错误页面都不返回。例如,阻止不带合法Referer的POST请求,或者屏蔽特定的恶意UA字符串。把这些规则写在http段,通过map定义变量,在server段统一判断,性能损耗极低。
操作系统内核参数的深度调优Linux内核默认参数是为通用场景设计的,面对DDoS必须调整TCP/IP协议栈行为。核心在于缩短超时时间、加大积压队列、开启SYN Cookie和优化连接回收。
编辑/etc/sysctl.conf文件,应用以下参数。net.ipv4.tcp_syncookies=1是必选项,它让服务器在SYN队列满时发送带Cookie的SYN-ACK,不占用半连接队列,有效防御SYN Flood。net.core.somaxconn和net.ipv4.tcp_max_syn_backlog需要调大,比如分别设为65535和8192,增大全连接和半连接队列长度,吸收突发流量。net.ipv4.tcp_synack_retries设为1或0,减少SYN-ACK重试次数,快速释放半连接资源。
对于连接回收,net.ipv4.tcp_fin_timeout默认60秒,可以降到15或10秒,让TIME_WAIT状态的连接快速回收。启用net.ipv4.tcp_tw_reuse=1允许将TIME_WAIT连接用于新连接,缓解端口耗尽。但注意tcp_tw_recycle在较新内核中已被移除,且对NAT环境不友好,不要使用。net.ipv4.tcp_keepalive_time从7200秒降到600秒,net.ipv4.tcp_keepalive_intvl降到30秒,net.ipv4.tcp_keepalive_probes设为3次,这样能更快检测并断开死连接,释放文件句柄。
还需要调整net.netfilter.nf_conntrack_max和超时时间,如果服务器开启了iptables或firewalld,连接跟踪表很容易被DDoS打满。把hashsize和max都调大,同时用net.netfilter.nf_conntrack_tcp_timeout_established调低已建立连接的超时,比如设为600秒。这些参数组合在一起,能让单台服务器的TCP栈从“彬彬有礼”变成“快进快出”的模式,极大提升抗压能力。
巧用CDN的隐藏功能构建前置防线CDN不仅是内容缓存,更是无硬件DDoS防护中最强大的分布式清洗网络。但要用好它,不能只做简单的CNAME解析,必须利用其安全特性。首先,开启CDN的DDoS防护模式,通常叫“Under Attack”模式或高级安全策略。这会开启JavaScript挑战和人机验证,在流量到达源站前就拦截掉自动化攻击脚本。
最关键的一步是源站白名单机制。在Nginx或iptables上配置,只允许CDN的回源IP地址段访问80和443端口,其他所有IP直接丢弃。这样攻击者绕过CDN直接攻击源站IP的任何尝试都会失败。你可以在Nginx的server段用allow和deny指令实现,或者在iptables的INPUT链最前面插入规则,只放行CDN的IP列表。CDN提供商会定期更新其IP段,你需要写一个定时脚本从CDN的API或公开页面拉取最新列表并更新防火墙规则。
利用CDN的速率限制和WAF规则。大多数CDN提供在边缘节点配置速率限制的功能,你可以设置比源站Nginx更宽泛的阈值,让CDN承担大部分压力。配置WAF规则拦截SQL注入、XSS和恶意扫描,这些攻击常作为大流量DDoS的掩护。此外,配置缓存策略,将静态资源的缓存时间设长,对于动态内容,利用CDN的“缓存一切”规则配合查询字符串忽略,把半静态的API响应也缓存几秒到几分钟。当攻击发生时,大量请求被CDN边缘节点直接响应,源站几乎无感。
利用Anycast和DNS层面的流量调度Anycast技术并非只有大厂能用,你可以在DNS层面实现简单的流量分散。如果你有多台位于不同数据中心的VPS,可以给它们配置相同的服务,然后在DNS解析上做文章。使用支持Anycast的DNS托管服务,或者自建多节点DNS,将域名的A记录指向多个IP。当用户解析时,DNS会根据网络拓扑返回最近的节点IP,天然分散了流量。
更高级的做法是利用健康检查和故障转移。在DNS层面配置监控,当某个节点因攻击不可用时,自动将其从解析记录中剔除。这需要你的DNS服务商支持API,你可以写脚本检测节点状态并动态更新记录。结合多节点Nginx反向代理,你可以构建一个简易的分布式防御网络。每个节点都配置好上述的内核和Nginx优化,前端再用DNS做基于地理位置的智能解析,将不同区域的流量引导到不同节点,避免单点被集中攻击。
对于UDP类的放大攻击,比如NTP、DNS反射,这些流量通常直接涌向服务器IP。如果你使用了CDN,源站IP不应对外提供服务。但你仍然可以在服务器上通过iptables限制UDP流量。只放行你需要的UDP端口,比如53端口如果你自建了DNS,其余全部DROP。对于必要的UDP服务,使用ratelimit模块限制每秒包数。在Nginx层面无法处理UDP,所以这部分必须在内核或防火墙层解决。
应用层防御:人机识别与行为分析当HTTP/HTTPS流量到达Nginx时,在转发给后端应用之前,可以插入一层轻量的人机识别。这不需要独立的硬件WAF,用Nginx的Lua模块就能实现。OpenResty集成了LuaJIT,你可以编写Lua脚本,在access阶段分析请求头顺序、TLS指纹、鼠标移动或点击事件(通过注入JavaScript)来判断是否为真实浏览器。
一个有效的技巧是检查TLS JA3指纹。恶意脚本通常使用特定的TLS库,其握手特征与真实浏览器不同。你可以在Nginx的SSL握手阶段记录JA3指纹,与已知的浏览器指纹库对比,对不匹配的直接返回403。这需要编译Nginx时加入SSL指纹模块,或者通过Lua调用外部程序分析。另一个方法是设置Cookie挑战。当请求到达时,返回一个302重定向并设置一个特殊Cookie,同时返回一段JavaScript代码要求客户端计算一个数学难题并重定向回来。自动化脚本通常不会执行JavaScript,因此会被过滤。Nginx的Lua模块可以轻松实现这种逻辑,性能开销很小。
对于JSON API,可以基于请求体的结构进行异常检测。正常的客户端请求体结构相对固定,攻击脚本往往发送畸形或随机数据。在Nginx的Lua脚本中,你可以对请求体做简单的模式匹配,发现异常直接拒绝。还可以结合Redis记录IP的行为分数,对短时间内触发多个404、请求不存在的路径、高频访问同一资源的IP进行降权或临时封禁。这套逻辑完全在内存中运行,延迟极低。
日志与监控的降级策略DDoS攻击期间,日志写入可能成为系统瓶颈。Nginx的access_log会疯狂写入磁盘,导致IO飙升。必须立即降级日志。在http或server段,将access_log关闭,或者设置为off,或者通过buffer和flush参数异步写入。更彻底的做法是将其重定向到/dev/null。同时,error_log的级别调高到crit,只记录严重错误。
实时监控不能依赖日志文件,改用Nginx的stub_status模块或通过Lua脚本将关键指标推送到内存数据库如Redis或时序数据库。你可以用Lua编写一个简单的计数器,统计每秒的状态码数量、请求数、当前连接数,并通过UDP包发送到监控收集器,避免TCP握手开销。这样即使在攻击中,你也能看清服务器的真实负载和过滤效果,而不会被日志IO拖死。
终极手段:TCP层级的无状态防御如果攻击流量巨大,连Nginx都来不及处理SYN握手,你需要将防御下沉到TCP层。利用iptables的hashlimit模块可以实现无状态的IP速率限制。与Nginx的limit_req不同,hashlimit在netfilter层面工作,不创建用户态连接,效率极高。例如,限制每个IP每秒最多新建20个TCP连接:
iptables -A INPUT -p tcp --dport 80 -m hashlimit \
--hashlimit-name http_new \
--hashlimit-above 20/sec \
--hashlimit-burst 30 \
--hashlimit-mode srcip \
-j DROP
另一个技巧是使用tc(Traffic Control)对流量进行整形。你可以创建一个简单的令牌桶过滤器,对发往80端口的流量进行全局速率限制,丢弃超过阈值的包。这能防止服务器带宽被完全占满,为SSH管理等关键流量保留通道。
这些轻量化技巧的核心逻辑是分层过滤:CDN和DNS做第一层地域级分散和粗粒度清洗,内核参数和iptables做第二层协议级过滤,Nginx做第三层应用级精确拦截和速率控制,最后Lua脚本做第四层行为分析。每一层都只让合法的、低频率的请求通过,攻击流量在到达应用代码前就被层层剥离。没有硬件设备,你依然可以通过软件定义的防御体系,把单台普通云服务器的抗DDoS能力提升一个数量级。
