ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

DDoS攻击原理与防御实战:从应急到体系构建

DDoS攻击原理与防御实战:从应急到体系构建

1. 从一次实战说起:我为什么开始认真研究DDoS

事情要从两年前的一次上线说起。当时某个产品刚做完压测,自认为扛得住一定流量,结果正式对外不到一周,运营同事早上发来消息:“后台监控曲线不对劲,请求量突然翻了二十倍,但PV没涨。”

我登录服务器看了一眼,Nginx日志里铺天盖地的都是同一个URL,User-Agent五花八门,来源IP遍布全国,但有一个共同特征——单个IP的请求频率极高,而且请求的页面全是耗CPU的动态接口。那一刻我就意识到,这不是正常流量,是有人在打我们。

后面查下来,是同行竞争期间的一次恶意攻击。规模不算大,峰值也就每秒几千请求,但对当时只有几台小机器的团队来说,已经足够把服务打到超时。从那天开始,我花了大半年时间系统性地研究DDoS,从原理到防御、从应急到复盘,踩了不少坑,也积累了一些自己的心得。

这篇文章就是把这段时间的实践整理成一份相对完整的记录。不管你是运维、后端开发,还是自己捣鼓小项目的独立开发者,我都尽量用说人话的方式把DDoS这件事讲清楚——它是什么、怎么打、怎么防、真的遇到时怎么办。其中很多内容是基于我自己实际操作的补充和总结,不是教科书式的理论堆砌,希望能给你一些真正可落地的参考。

2. DDoS不是一种攻击,而是一类攻击的集合

很多人一听到DDoS,脑子里就浮现出“有人疯狂刷你服务器”的画面。这个理解没错,但不够精确。DDoS的全称是分布式拒绝服务攻击,拆开看有三个关键词:分布式、拒绝、服务。分布式意味着攻击源不止一个,而是成千上万个节点同时发起;拒绝服务的核心目的不是偷数据、改文件,而是让你的服务无法响应正常用户请求。

这决定了DDoS的防御思路和传统安全攻击完全不同。你不需要防住黑客进入系统,你需要防住的是海量垃圾流量把带宽打满、把连接耗尽、把CPU跑死。换句话说,攻击者不追求攻破你,只追求拖垮你。

按攻击层面去分,我习惯把DDoS分成三类:

  • 网络层攻击,典型的是SYN Flood、UDP Flood、ICMP Flood,目标是打爆带宽或者打满防火墙会话表。
  • 传输层攻击,比如TCP连接耗尽、SSL握手攻击,目标是把服务器的并发连接资源榨干。
  • 应用层攻击,比如HTTP Flood、慢速攻击、频繁请求某个高计算量接口,目标是消耗CPU、数据库连接、业务逻辑处理能力。

这里我特别想说一下应用层攻击。很多人买高防服务器,觉得自己带宽足够大,网络层攻击无所谓,结果一遇到HTTP Flood就傻眼。原因很简单:网络层攻击打的是管道的粗细,应用层攻击打的是管道里货物的处理速度。就算你的带宽有100G,如果应用层逻辑一个请求要查库三次、还要做一堆计算,几十并发就能把数据库连接池打满。

所以,理解DDoS的第一件事,就是先分清你面对的攻击属于哪一层。不同层级的防御手段完全不同,买错了防护等于白花钱。

3. 攻击者为什么能“借用”这么多机器打你

DDoS最可怕的地方在于它的规模。单台机器就算再厉害,也很难把一个大带宽打满,但如果是几万台机器同时发包呢?这就涉及到一个经常被误解的概念:僵尸网络。

攻击者控制的这些机器,大多不是他自己的。常见来源有几类:一是被植入木马的服务器和个人电脑,攻击者通过漏洞批量控制后等待指令;二是物联网设备,比如摄像头、路由器、智能网关,很多设备出厂默认口令没改,被人抓去组成了肉鸡;三是开放的DNS服务器、NTP服务器、Memcached等,这些可以被用来做反射放大攻击。

反射放大的原理值得单独拿出来说。攻击者伪造受害者的源IP,向公网上大量开放服务发送一个小请求,服务响应时把大结果发给受害者。响应的数据量是请求的几十倍甚至几百倍,攻击者只需要很小的带宽就能驱动巨大的流量打到受害者身上。这就是为什么我们经常看到新闻报道某次攻击峰值达到几百G甚至上T——背后不一定是真正的僵尸网络有多大,而是利用放大效应把流量“借”了出来。

对我个人而言,理解这一点最大的价值在于:防御时不要试图去区分“哪个IP是攻击IP”,因为攻击源可能遍布全球,甚至很多合法IP也在参与。更好的思路是站在受害者的角度,用流量特征和协议行为去做判断。

4. 防御DDoS的标准姿势:三层防线

我自己做防御的框架,可以简单概括为“清洗、限速、扩容”三个字。听起来简单,但具体操作每一步都有讲究。

4.1 第一层:流量清洗,把脏流量挡在门外

流量清洗是目前最主流的商业防护方案。原理是在你的服务器前面架设一层专门的清洗设备或高防节点,所有流量先经过它,实时分析后把攻击流量过滤掉,只把正常流量转发给你的源站。

这里有个关键概念叫“回源”。清洗节点怎么判断一个请求是否正常?标准做法是把请求的一些特征转发给源站试一下,源站能正常应答就放行,否则拦截。这有点像机场安检,看起来每个旅客都要过一遍,但真正耗时的检查只是针对可疑对象。

实际使用中,清洗方案的配置有几个要点:

  • CNAME接入:把域名解析到高防IP,由高防节点代理转发,这样攻击流量先到高防,被清洗后再回源。
  • 源IP保护:不能让攻击者知道你的真实服务器IP,否则他可以绕过高防直接打源站。常见做法是只允许高防IP访问源站,或者用防火墙限制回源IP。
  • 防护阈值设置:不是把所有流量都当攻击,只有当流量超过设定阈值时才触发清洗。阈值设太低容易误杀正常业务,设太高又起不到保护作用。

我见过很多团队把高防买回来就完事了,源站IP直接在DNS解析里暴露着,结果攻击者一封TCP包直接打源站端口,高防形同虚设。这是排第一位的低级错误。

4.2 第二层:应用层限制,让业务自己扛一部分

流量清洗可以扛住大流量,但在应用层攻击面前,单纯靠带宽清理是不够的。我们还需要在业务层面做一些手脚,让攻击请求进不到真正消耗资源的逻辑里。

这一层的做法比较灵活,我在项目中常用这几个:

  • 频控:针对同一IP、同一Cookie、同一设备指纹设置访问频率上限,超过阈值直接返回验证码或拒绝。核心是“正常用户不可能每秒请求一百次”。
  • 验证码:对于高频风险操作,比如登录、下单,强制加入滑块或点击验证,增加攻击成本。
  • 页面缓存:对不涉及个人数据的页面尽量静态化或用CDN缓存,动态请求尽量加一层Redis缓存,减少回源到数据库的请求。
  • 请求特征拦截:通过对User-Agent、Referer、请求头顺序等做规则匹配,拦截明显的恶意请求。但注意,这个方法只能对付初级攻击者,会伪造请求头的黑客很容易绕过。

我特别想强调频控的一个细节:不要只做IP维度的限频。现在很多攻击者会用分布式IP池,每个IP只发少量请求,如果只按IP限制,根本不起作用。我习惯的做法是组合维度:IP+User-Agent、IP+Cookie、或者用JavaScript生成的访问Token做设备指纹识别。当然这需要在前端埋点,算是一种成本略高的方案,但实测效果比单纯IP限频好很多。

4.3 第三层:基础扩容,把受害面降低

这里说的扩容不是无限买机器,而是合理规划冗余。比如:

  • 带宽冗余:至少保证日常峰值带宽的2至3倍冗余,避免小规模攻击一打就断外网。
  • 连接数优化:调整系统的文件描述符上限、TCP连接队列大小、Nginx的worker_connections,让服务器在连接压力下能撑更久。
  • 多节点部署:有条件就把业务部署在多地域或多可用区,配合DNS轮询或全局负载均衡,即便单一节点被打瘫,也能切流量到其他节点。

但我要泼一盆冷水:扩容只是延缓被击倒的时间,并不能根治DDoS。面对动辄几百G的大流量攻击,你本地服务器再扩容也是杯水车薪。所以扩容的正确角色是“为清洗节点争取时间”,而不是“硬抗攻击”。

5. 遇到DDoS时的应急实战流程

理论讲再多,不如把一次真实的应急过程拆开看。以下是我自己在一次攻击中实际操作过的流程,整理成了标准步骤,适用于大部分人遇到的“中小规模攻击”。

5.1 第一步:确认攻击特征,别自己吓自己

看到监控突然报警,第一反应不是急着开高防,而是先确认这到底是不是DDoS。我通过下面几个维度快速判断:

  • 流量曲线:如果流量在一分钟内飙升,同时正常业务量没有上升,大概率是攻击。
  • 请求来源分布:正常用户请求的IP是分散的,如果某个IP段或某些地区占比异常,或是大量IP使用相同UA,就要警惕。
  • 业务指标:CPU升高、数据库慢查询增多、接口响应时间大幅上升,但不是因为某个功能上线或活动推广,这多半也指向攻击。

我遇到过好几次“假警报”,比如某个爬虫脚本跑挂了疯狂重试,或者某个业务接口没有做缓存被用户频繁刷新,流量特征看起来也吓人,但本质不是DDoS。确认清楚再动手,能省下很多不必要的购买和配置成本。

5.2 第二步:先拉黑,再溯源

如果确认是攻击,最快速有效的止损手段就是精确封禁。不要试图用防火墙一条一条封几千个IP,那样效率太低而且容易误伤。

我的做法是:先根据Nginx访问日志,用awk按IP统计请求次数,找出前100个高频IP,然后批量写入防火墙黑名单。这一步能在几分钟内干掉一部分明显攻击。同时开启SYN Cookie、限制单IP并发连接数,这些内核参数能缓解连接耗尽型攻击。

# 示例:统计Nginx日志中请求次数前20的IP awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -20

如果你比较熟悉系统配置,可以临时调整内核参数来增强抗压能力:

# 开启SYN Cookie,缓解SYN Flood echo 1 > /proc/sys/net/ipv4/tcp_syncookies # 增大TCP半连接队列长度 echo 1024 > /proc/sys/net/ipv4/tcp_max_syn_backlog

但这些只是应急,真正的解药还是要靠流量清洗。

5.3 第三步:接入高防,切换解析

如果攻击规模超过了你本地服务器的承受能力,就不要再硬扛了。赶紧把DNS解析切到高防IP,或者直接在CDN控制台开启DDoS防护。

切解析之前一定要确认高防回源地址填的是你的源站IP,并且源站防火墙只允许来自高防节点的流量访问,否则攻击者一旦拿到源IP,绕过高防直接打源站,前面做的全是白费。

有一个细节容易忽略:DNS解析有TTL缓存,切换后可能15分钟到几小时才完全生效。在这个“生效窗口期”里,攻击可能仍然直接打到你的服务器上。所以务必备份好防火墙规则,随时准备继续用你手上的IP封禁来拖延时间,等解析切完之后再松口气。

5.4 第四步:事后复盘,把攻击变成防御经验

攻击结束后,别急着关掉日志,赶紧复盘。我通常会统计这些信息:

  • 攻击峰值流量和持续时间,对比高防防护阈值的设置是否合理。
  • 攻击主要属于哪一层,是SYN Flood还是HTTP Flood,分析攻击者的手法。
  • 哪些防护规则生效了,哪些规则形同虚设,需要怎么调整。
  • 业务侧有没有被误伤,正常用户是否受到牵连,验证码和频控的阈值是否需要优化。

这些数据如果收集保存好,会是你后续优化防御策略最重要的依据。

6. 各层级攻击的排查与应对速查表

为了日常查阅方便,我把常见的攻击类型、特征、应急预案整理成一个速查表。这是我实际工作中使用频率很高的一个表,你可以直接参考:

攻击类型典型特征初步应对手段长期防御建议
SYN Flood大量半连接请求,TCP队列被打满开启SYN Cookie,调整tcp_max_syn_backlog接入防火墙SYN代理或高防
UDP Flood大量UDP小包或大包,带宽跑满丢弃非业务端口UDP包,限制单IP UDP流量使用高防流量清洗
HTTP Flood请求频率高,多为动态URL,UA异常Nginx层做频控,封禁异常UA和IPCDN+WAF,组合频控
慢速攻击连接建立后长时间不发送数据缩短超时时间,限制单连接最大请求数开启slowloris防护模块
DNS反射放大流量来源指向DNS服务器,端口多为53关闭无关DNS端口,限速源端口53高防清洗,源站隐藏

这个表里我只列出了我在实践中遇到的几种典型场景。实际攻击往往混合多种手法,比如先SYN Flood打一阵子,再转HTTP Flood,让你防御措施还没来得及调整就被打穿。所以平时多做演练,到了关键时刻才能快速反应。

7. 长期防御体系的构建思路

应急手段解决的是“正在被打”的问题,长期防御解决的是“以后怎么少被打、被打不怕”的问题。我自己的实践经验,可以压缩成下面几个核心点。

7.1 隐藏源站是第一优先级

很多团队买了高防却依然被轻松打穿,原因十有八九是源站IP泄露了。泄露渠道通常有三个:

  • DNS历史解析记录。攻击者可以通过第三方历史DNS查询到切换前源站的IP。
  • 网站子域名。很多业务有管理后台、测试子域、API接口直接解析到了源站,而忘了加防护。
  • 邮件头、源代码、证书透明度日志等。某些信息会无意中包含真实IP。

所以,长期防御的第一步不是买设备、买带宽,而是做一次源站信息梳理。把公网可以探测到的所有入口全部收敛,确保只有高防节点能够访问源站。

7.2 CDN和高防不是同一个东西

很多新手会把CDN和高防混为一谈。CDN的核心是缓存加速,虽然也带一些DDoS防护能力,但主要针对的是静态资源和网络层攻击。如果你的业务大量动态请求、计算密集,CDN的防护能力就会大打折扣。

高防则是专门为抗流量攻击设计的,具备更强的流量清洗能力。合理的方式是两者结合:静态资源走CDN,动态请求走高防,并通过一个各域的入口统一管理。这样既能保证速度,又能获得更强的抗D能力。

7.3 防火墙规则和WAF规则要分层

我看到很多团队把所有安全的希望寄托在一台防火墙设备上,这是个很大的误区。防火墙擅长基于IP、端口、协议做粗粒度过滤,但面对应用层攻击时,它看不到请求内容,自然无法精准拦截。

所以我会建议在防火墙之上再加一层WAF,用于HTTP请求的深度检测。WAF可以通过规则识别恶意Payload、SQL注入、XSS、恶意爬虫等应用层攻击特征,与防火墙的流量过滤形成互补。

7.4 监控预警比扛住攻击更重要

有的团队直到用户反馈“网站打不开”才知道被攻击了,这种被动局面非常危险。我强烈建议搭建一套基于流量和业务指标的多维度监控告警体系,至少包含以下指标:

  • 总入向带宽、出向带宽,超过阈值自动告警。
  • Nginx的活跃连接数、请求处理速率,与历史基线做对比。
  • 业务接口的响应时间、错误率,异常时触发通知。
  • 系统层指标:CPU、内存、TCP连接数、SYN_RECV状态数量。

通过监控数据,可以把攻击识别缩短到秒级,而不是靠用户投诉来发现问题。

8. 工具选型与成本思考:不同预算怎么选方案

关于防御工具,市面上有各种名称和方案,价格也是天差地别。我根据自己的实践和观察,把不同预算的选型建议整理一下,供参考。

如果只是一个个人博客或小型创业项目,预算有限,那可以考虑使用有基础防护的云服务商所提供的免费DDoS防护服务,配合CDN把攻击流量分散。同时自己用脚本做简单的IP封禁和频控。这套组合能扛住一些小规模攻击,但面对大流量攻击时仍会力不从心。

如果是正式商业产品,预算有一定余量,那么直接购买专业的高防IP服务是性价比最高的选择。建议按照业务峰值流量的3倍左右去购买防护带宽,同时配置源站保护。这部分费用看似昂贵,但比起被攻击后业务中断、用户流失带来的损失,其实是划算的。

如果业务规模较大、对稳定性要求极高,那就需要考虑自建或者采购更高级的流量清洗系统,配合多地域牵引、Anycast等方案。这一层已经属于运营商级别的防护,不是一般团队自己能搭建的,需要专业的网络团队支撑。

还有一个很多人会忽略的成本点是:攻击流量不只是外部对源站的流量,还包括你回源到高防的流量。有些高防服务按“清洗后回源流量”另外计费,如果业务本身流量就大,这是一笔不小的隐性成本。购买之前一定要看明白计费规则。

9. 我踩过的几个坑,希望你避开

理论讲完,分享一下我真实踩过的坑。以下每一个都损失过时间、金钱或者数据,分享出来希望大家少走弯路。

第一个坑:只测防护带宽,没测并发连接数。高防服务商宣称100G防护能力,买回来也确实能扛住大流量,但攻击手法是大量慢连接,耗尽服务器连接资源。结果带宽没打满,服务却已不可用。后来才明白,防护能力不是只有一个“带宽”维度,并发连接数、连接速率、应用层请求速率都需要关注。

第二个坑:切换高防后忘改源站安全组。当时确认攻击后光速买了高防、切了CNAME,结果忘了把源站的入口限制为只允许高防回源。攻击者顺着旧的解析记录找到源站IP,直接打源站端口,高防完全没起到作用。自那以后,我把“源站保护”写进了应急清单,切换后必查。

第三个坑:过度依赖IP黑名单。早期遇到攻击时,我习惯于不断往黑名单里塞IP,结果黑白名单越加越长,正常流量也受到影响,甚至某省份的用户因为我们封的IP段过宽直接无法访问。现在我做限频和封禁的规则都是动态的,优先使用验证码来拖慢攻击者,而不再简单粗暴地封IP段。

第四个坑:忽视了业务自身的健壮性。有一次遇到应用层攻击,攻击者专门请求一个需要大量计算和查库的报表接口,这个接口本身没有做频控和缓存,服务商的高防也只做了网络层清洗,没有针对这个接口做防护。结果高防没报警,业务却已经变慢到不可用。从那以后,我把核心接口的限流、缓存、幂等等设计纳入了研发规范,这其实比任何安全设备都更有效。

10. 写在最后的个人体会

做了这一轮DDoS的实践和研究,我最大的感受是:DDoS防御没有一劳永逸的银弹,它是一个持续对抗、持续优化的过程。今天你用IP限频挡住了攻击者,明天他就换分布式代理;今天你买了高防扛住了大流量,明天他就学精了,改用低频慢速攻击绕过规则。

但换个角度想,防御方也不是完全被动。攻击者的成本是持续攻击,你的成本是持续优化。只要你的体系能不断根据攻击特征迭代,让攻击成本远高于你防御的成本,对方就会慢慢放弃你。

所以我建议所有正在做在线业务的朋友,不用追求一步到位的安全等级,而是先打好基础:隐藏源站、搭建监控、基础限频、备份应急方案。这些东西花不了太多钱,但能在真正被攻击时为你争取到足够的时间,去启动更高一级的防护方案。

最后再分享一个习惯:我每隔一段时间会自己做一次DDoS攻防演练,用测试工具模拟半分钟的小规模攻击,检验防护规则是否有效、告警是否及时。每次演练都能发现一些平时想不到的问题。有空你也可以试试。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进