凌晨两点,手机被值班同事的电话吵醒。APP登录接口的监控大屏飘红,用户反馈一批接一批涌进来:支付超时、页面白屏、刚登录的账号被强制退出。一开始还以为是发布新版本引发的兼容问题,结果一查Nginx日志,全是同一类畸形请求,每秒几千次,CPU直接被打满。那一刻我心里反而踏实了——这不是故障,是攻击。只要确认是攻击,就意味着有对策。
这类事情,这几年我经历过不止一次。从最初的DDoS流量打到带宽跑满,到后来越来越隐蔽的CC攻击、反序列化注入、批量撞库,攻击者的手法越来越“精细化”,单纯靠买高防或者关停服务器,根本解决不了问题。真正能让你从被动挨打变成主动防御的,是一套完整的应急响应流程,再加上事件结束后的长效机制建设。
这篇就是把我在实战中沉淀下来的经验整理出来,从确认攻击类型、止血、取证、溯源,到恢复业务、复盘整改、建立“免疫”体系,一条线讲清楚。不管你是在创业公司做后端,还是在成熟的研发团队负责运维安全,这篇文章的流程和排查思路都可以直接拿过去用。对于刚接触安全的小白,我也尽量把每个环节背后的原理讲明白,让你不仅知道“怎么做”,更知道“为什么这么做”。
1. 先搞清楚:你面对的到底是哪种攻击
1.1 不是所有“挂掉”都叫被攻击
先要泼一盆冷水。做应急响应这么多年,我接手过很多“疑似攻击”的case,最后排查下来大概有三分之一根本不是攻击,而是自己的问题——数据库连接池耗尽、慢SQL拖垮主库、缓存雪崩、发布脚本误操作。所以应急响应的第一步,永远不是急着封IP,而是先确认现象,排除掉自身的容量、代码和配置问题。
举个例子。某次客户说APP被攻击了,接口大量超时。我上去看监控,发现应用服务器CPU才30%,但数据库服务器的IO等待非常高。拉出慢查询日志一看,有一条SQL是因为新上线的列表页没有加索引,全表扫描把数据库拖死了。这属于典型的性能事故,不是安全事件。如果当时直接上WAF封IP,问题根本不会解决,反而会把真正的性能瓶颈掩盖掉,甚至误伤正常用户。
判断是不是攻击,有几个快速信号:
- 流量特征是否异常:请求量突然暴涨,且来源IP非常集中,或者UA、Referer明显异常
- 行为特征是否异常:大量请求集中在某几个业务接口,比如登录、验证码、支付回调
- 数据特征是否异常:请求参数里含SQL关键字、命令注入字符、编码后的恶意Payload
- 业务端反馈是否异常:用户大面积反馈账号被盗、数据被篡改、收到异常短信
如果这几个信号同时出现,基本可以确定是攻击。如果只是单个指标波动,先查系统容量和代码逻辑。别小看这一步,它能帮你省下大量无效动作。
1.2 攻击类型速识:从现象反推原因
不同攻击类型的表现差异很大。我平时会把APP常见的攻击场景分成几类,每类都有标志性的“症状”,对照着看,响应速度会快很多。
第一类:流量型攻击。典型代表是DDoS,把带宽或者服务器的连接数打满,表现为整个APP变慢、打不开,所有用户一视同仁受影响。攻击目标往往是网络出口、DNS解析或某个接口。这类攻击不需要你的应用有什么漏洞,纯粹靠流量堆死你。
第二类:资源消耗型攻击。典型代表是CC攻击,模拟大量真实用户请求某个业务接口,把后端服务或数据库压垮。它跟DDoS的本质区别是:单个请求看起来完全正常,但请求量巨大,而且集中在特定API上。很多APP被攻击后CPU飙升、接口大面积超时,排查下来就是这种。
第三类:漏洞利用型攻击。包括SQL注入、XSS、反序列化、命令注入、文件上传等。这类攻击有明确的Payload特征,通常会在日志里留下痕迹。它们的危害往往不是“打不开”,而是“被拖库”“被挂马”“被植入后门”。反序列化攻击在Java系APP里尤其常见,攻击者构造一段恶意序列化数据,服务端一解析就被RCE。
第四类:业务逻辑攻击。比如撞库、短信轰炸、优惠券刷单、支付篡改。这类攻击不依赖漏洞,纯粹利用业务设计上的缺陷。很多团队最容易忽略它,因为从日志上看,每个请求都是“合法”的,直到业务数据出现异常才暴露。
第五类:链路与终端攻击。比如NFC中继攻击、本地抓包篡改请求、服务路径劫持、弱口令爆破。这类攻击的入口不在云端,而在用户的终端或网络链路上。做APP开发的同学应该都体会过:自己的请求被Fiddler一抓,参数改一改,服务器根本不校验,这就是终端侧信任问题。
搞清楚类型之后,才能决定后续动作。流量型攻击靠清洗和调度,漏洞利用型攻击靠WAF和代码修复,业务逻辑攻击靠风控规则和产品改造。用错药方,既浪费人力,也耽误时间。
2. 应急响应的正确打开方式
2.1 组建小队,明确分工
发生攻击时最怕什么?最怕一群人围着服务器七嘴八舌,你改一下我改一下,最后连谁做了什么都不知道。所以我到现场后的第一个动作,永远是先拉一个小群,把角色定下来。
一个标准的应急响应小组,建议至少覆盖四个角色:
- 指挥协调人:通常是技术负责人或指定的运维主管,负责拍板、调度资源、对外沟通
- 应用排查人:后端开发,负责排查接口逻辑、代码漏洞、业务日志
- 基础设施排查人:运维,负责查网络流量、服务器负载、防火墙、WAF配置
- 记录与发布人:负责整理时间线、截图留存、写公告、通知相关方
这个分工不是随便定的。很多时候攻击发生的第一现场是监控告警,第二现场是用户投诉,如果不指定专人记录,很容易漏掉关键证据。我习惯在群里把所有操作按时间线记录下来,比如“10:05 封禁IP段A”“10:11 回滚到v1.3版本”之类的,这样复盘的时候能精确还原整个处置过程。
2.2 定级与决策:先保什么
定级是整个应急响应的决策基础。我们平时会按影响范围把事件分成四级,不同级别对应不同的响应强度:
| 事件级别 | 判断标准 | 响应动作 |
|---|---|---|
| 一级 | 服务不可用、资金损失、大面积用户受影响 | 立即启动应急小组,暂停发布,优先恢复业务 |
| 二级 | 部分接口异常、少量用户数据泄露 | 2小时内完成止血,24小时内定位根因 |
| 三级 | 攻击尚未造成实际影响,只发现攻击迹象 | 持续监控,评估风险,安排修复窗口 |
| 四级 | 内部测试或扫描发现风险点 | 按常规缺陷流程处理 |
定级的关键是“先保什么”。如果APP已经无法访问,那么当务之急是恢复可用性,而不是追凶。如果业务还正常,但日志里发现了SQL注入痕迹,那就要谨慎处理,因为攻击者可能已经拿到数据,你需要第一时间排查数据库是否被拖取。如果涉及用户密码、支付信息这类敏感数据,还需要考虑是否通知用户修改密码、是否冻结异常账号,必要时该报警就报警。
这里有一条我个人的经验:应急响应的首要目标不是“找到攻击者”,而是“控制损失”。很多团队花大量时间去拦截攻击者,却忘了最要紧的数据保全和恢复业务。记住,攻击者以后再抓,但业务每停一分钟,损失都是实打实的。
3. 止血:让攻击停下来的关键动作
3.1 流量型攻击的临时缓解
确认是DDoS或CC攻击后,止血动作要快。先看监控,确定打的是带宽、连接数还是某个API。如果是带宽被占满,能做的临时手段不多,最有效的是接入高防服务,通过DNS切流把攻击流量导入清洗节点,让干净流量回源到源站。需要提醒的是,高防切流生效需要一点时间,而且如果你源站IP已经暴露,攻击者很可能会绕过高防直接打源站,所以在清洗的同时,最好更换源站IP或者开启CC防护策略。
如果打的是连接数,比如大量半开连接占满Nginx的worker连接,可以考虑在系统层面做限制。Linux内核参数里那几个常见的连接超时、SYN重试参数可以临时调一下:
# 减小SYN重试次数,加快释放半开连接 sysctl -w net.ipv4.tcp_synack_retries=1 sysctl -w net.ipv4.tcp_syn_retries=1 # 缩短TIME_WAIT等待时间 sysctl -w net.ipv4.tcp_fin_timeout=15但要注意,这些只是“把容量腾出来”,治标不治本。真正的临时封禁还是要靠WAF或云厂商的DDoS防护策略。Nginx层面可以做基础的请求频率限制,比如限制单个IP的并发连接数和请求速率:
limit_req_zone $binary_remote_addr zone=perip:10m rate=20r/s; limit_conn_zone $binary_remote_addr zone=peraddr:10m; server { location /api/ { limit_req zone=perip burst=40 nodelay; limit_conn peraddr 10; } }这段配置的含义是:每个IP的请求速率被限制在每秒20次,允许突发40次请求进入排队;同时每个IP最多同时保持10个连接。对于正常的手机用户来说,这个阈值基本不会误伤;但对于CC攻击来说,单IP的高频请求会被直接挡掉。当然,如果攻击方有能力调动大量IP,Nginx层面的限制就失效了,必须依赖WAF和云防护的智能识别。
3.2 应用层漏洞的快速拦截
如果攻击是利用应用漏洞,比如SQL注入、反序列化、文件上传,最有效的手段是先在网络入口处拦截,让恶意请求进不了业务逻辑层。
以SQL注入为例,WAF通常有对应的规则集,可以在管理后台临时启用“SQL注入防护”模式。但WAF不是万能的,攻击者可以通过编码绕过、注释符混淆等方式绕过简单规则,所以不能只靠WAF“裸奔”。需要同时做两件事:一是确认漏洞点并紧急修复代码,二是把线上流量切换到防护更完整的链路。
Java系应用如果没有,这里重点说反序列化漏洞。反序列化攻击最麻烦的点在于,它不像是SQL注入那样有明显的SQL关键字,而是通过构造二进制数据流触发漏洞。临时止血的办法是把入口处的序列化数据流做严格的白名单校验,非业务要求的一律拒绝。有条件的话,直接升级到修复了漏洞的组件版本。像Jackson、Fastjson这类组件,历史上出过不少反序列化RCE漏洞,官方修复版本一定要及时跟进。
另外,文件上传漏洞也是应急里常见的高危项。临时止血可以关闭不需要上传的接口,必须在线的上传接口,则加上文件类型和内容校验。注意,不能只看文件扩展名,要读取文件头做魔数校验;上传目录要设置为不可执行权限,防止WebShell落地后被解析执行。
3.3 账号与密钥的兜底处理
攻击者可能已经拿到了部分账号或密钥。即使还没确认泄露,应急期间也应该把高权限账号强制下线并重置密码,包括数据库账号、云平台API密钥、SSH密钥、支付商户密钥等。这个动作看着麻烦,但很有必要——很多攻击事件拖了很久,就是因为攻击者用你忘了换的密钥,一直能进出系统。
还有一个容易忽略的地方:重置密码不等于只改一个密码。如果攻击者已经植入后门,修改密码前应检查是否有隐藏的管理员账号,是否有异常的计划任务,是否有新增的SSH公钥。否则你重置完密码,攻击者依然通过后门进出。我处理过的一个case就是,管理员改了root密码,但攻击者已经把公钥写进了~/.ssh/authorized_keys,你改密码对他毫无影响。
3.4 取证:留好每一份证据
止血阶段容易犯的错是:一着急就把服务器重启了,把日志清了,把进程杀了。这些动作都会破坏攻击现场,导致后续无法溯源。所以我在应急开始前,会先要求团队保留现场:
- 导出当前连接状态:
netstat -anp或者ss -tunap - 保留进程列表:
ps -ef,重点关注非系统路径下的进程 - 复制日志文件:nginx、tomcat、应用系统日志,尽量用副本操作
- 抓包存证:如果有条件,在攻击入口抓一段时间的流量保存为pcap文件
证据保留的重点是“时间”,所有操作尽量记录具体时间点,这样后续分析进攻时间线才能对齐。日志文件建议按天归档,不要只用一条命令把多个日志文件合并处理,防止覆盖原始信息。
4. 溯源:攻击者是怎么进来的
4.1 从日志里找第一现场
止血成功之后,就要开始溯源了。溯源的目的不是“抓到人”,而是搞清楚三件事:攻击路径是什么、数据是否泄露、后门是否还存在。
最常用的第一手资料是访问日志。拿Nginx的access.log来说,我一般会先统计攻击时段内的Top IP:
grep "2025-06-15T02:" access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -20把自己设想的攻击时间段替换进去,如果某几个IP的请求量占到总请求量的80%以上,那基本就是攻击源。接着看这些IP都访问了哪些路径,定位攻击目标是不是某个特定接口。
然后看UA。很多攻击脚本不会伪装UA,或者UA特征特别明显,比如Python的requests库、Go的http客户端、某个扫描器自带的UA。把异常UA单独筛出来:
grep "python-requests" access.log | wc -l grep "sqlmap" access.log | wc -l注意,这里不要只盯着UA,因为高级攻击者会用真实浏览器指纹。还要看Referer是否异常,看请求参数是否带有明显的编码特征,比如%27、%3Cscript%3E这类URL编码后的特殊字符。
4.2 提取攻击指纹,顺藤摸瓜
把日志里的攻击请求整理出来,提取攻击指纹,是溯源很关键的一步。指纹包括:
- 攻击Payload的固定格式
- 攻击者使用的工具特征
- 请求头顺序、Header字段的异常组合
- 攻击时间段的规律性,比如是否固定在某个时区的时间段
有了指纹,可以先在日志里全量搜索,看攻击从前天甚至上周就开始了。很多攻击不是临时起意,而是先扫描试探,确认漏洞后再发起第二波。如果你只看了攻击高潮期间的日志,很可能漏掉最开始的侦察行为。
这个时候可以结合WAF的拦截日志来分析。WAF通常已经沉淀了被拦截的恶意请求,把拦截记录和源站日志做交叉对比,往往能拼出完整的攻击链条。比如WAF记录显示某IP尝试了SQL注入,但源站日志里同一时段出现了该IP访问后台接口的记录,那就要警惕:攻击者可能已经用注入拿到的数据进入了后台。
4.3 用抓包工具还原攻击请求
在做移动端APP的应急时,抓包工具非常有用。我自己用得最多的是Fiddler和Charles。它们可以代理手机流量,让你看APP发出的每一个HTTPS请求。排查思路通常是:用抓包工具连上手机,复现用户遇到的异常场景,观察请求参数、响应内容,看是否有异常的第三方请求、是否有敏感数据明文传输、是否有隐藏的调试接口。
这里需要提醒一句,抓包只能在你有授权的环境下进行,抓包和分析自己开发的APP是没问题,但未授权抓取和分析他人服务就是越界行为了。
在排查反序列化攻击时,抓包的作用尤其明显。攻击者发送的序列化数据包通常带有特定的二进制头标识,抓包后一眼就能看出异常。还有个技巧:在抓包时同时开启手机端的系统日志,可以对照APP在发请求时的行为变化,快速定位是哪个组件在处理异常数据。
5. 恢复、复盘与长效免疫
5.1 业务恢复的顺序与验证
止血之后,业务恢复不能一窝蜂地“全量开放”。我给团队定的恢复顺序是:先恢复核心读接口,再恢复写接口,最后开放边缘功能。每恢复一个模块,都要做一次接口连通性测试和业务验证,确认没有问题之后再放量。
为什么这么做?因为攻击影响的不只是服务器,还可能污染了数据。比如撞库攻击会导致大量用户账号被锁定或异常,如果你直接全量开放登录,用户会集中涌入,可能引发二次故障。恢复服务之前,先把异常账号清理掉,把缓存预热好,再把服务逐步放行。
另外,恢复期间要保留监控的高频采样,至少观察30分钟,确认流量恢复平稳后再降低告警阈值。我见过不少团队,攻击停了就着急把WAF防护关掉,结果第二波攻击打过来又措手不及。记住,应急结束不等于攻击结束,至少要观察一段时间再降级防护策略。
5.2 复盘:把事件变成流程
很多人觉得复盘就是写个文档、开个会,然后没有然后了。我理解的好复盘,是让这次事件变成下一次的“防护网”。复盘报告至少要包含五块内容:
- 事件时间线:从首次告警到完全恢复,每一步做了什么
- 攻击画像:攻击类型、攻击路径、影响范围、攻击时长
- 根因分析:漏洞是什么、为什么没被发现、哪个环节漏了
- 响应评估:现有的预案是否有效、响应速度是否达标、协作是否顺畅
- 整改清单:明确每一项修复动作、负责人、截止时间
整改清单是最容易被人忽视的部分。没有整改清单,复盘会就是一场“集体检讨”,过两周大家全忘了。我习惯把整改项直接绑定到项目管理工具里,每条都指定负责人和验收标准,比如“5天内完成登录接口的全局限流”“2周内升级Fastjson到最新版本”“一个月内完成所有服务器的基线加固”。下次检查时,逐条打钩。
5.3 长效免疫:安全左移与持续防护
应急响应解决的是“已经发生的事”,而长效免疫解决的是“未来不再发生”。理想的思路是把安全工作“左移”到开发和发布环节,而不是等上了线才补窟窿。
具体来说,有几个方向值得投入:
- 安全开发流程:需求阶段就做威胁建模,开发阶段要求代码安全规范,自测阶段用静态扫描工具查漏洞
- 依赖组件管理:建立第三方组件清单,定期拉取漏洞库,发现高危CVE及时升级
- 上线前安全检查:每次发版前跑一次自动化漏洞扫描,高危问题不修复不发布
- 日志与监控告警:把关键业务接口的异常访问纳入监控,比如登录接口的失败率、单IP高频请求、接口超时率
- 风控与防刷:对登录、注册、验证码、支付等敏感接口,叠加验证码、滑块、设备指纹、频率限制等多重机制
- 权限收敛:数据库账号分权分库,最小化权限;SSH禁用密码登录,只允许密钥
这里我想额外说一点。长效免疫不是买一堆安全产品就能实现的。你买了一个很贵的WAF,但如果业务上可以随便上传文件,又没做内容校验,那WAF也只能拦住一部分。安全是系统工程,需要研发、运维、测试、产品一起参与。把安全当成每个人的责任,比单纯依赖安全团队更有效。
6. 常见问题与排查技巧实录
6.1 典型问题速查表
| 现象 | 可能原因 | 快速处理建议 |
|---|---|---|
| APP整体访问变慢或打不开 | DDoS流量攻击 | 接入高防清洗,切换流量,限制单IP连接数 |
| 某个接口CPU飙升、超时 | CC攻击或慢SQL | 加限流,定位慢查询,检查是否有异常高频请求 |
| 登录接口大量失败、用户反馈被盗号 | 撞库攻击 | 验证码策略升级,锁定异常IP,批量重置风险账号 |
| 日志中出现SQL关键字的请求 | SQL注入攻击 | WAF临时拦截,定位注入点,代码修复后发布 |
| 后台出现未知文件或脚本 | 文件上传漏洞/WebShell | 限制上传目录执行权限,检查WebShell并清除 |
| Java应用CPU占用异常、莫名其妙的RCE | 反序列化漏洞 | 升级组件版本,入口校验序列化数据,检查后门 |
| 用户扫码支付被篡改 | 本地抓包改参数 | 服务端增加签名校验和金额校验,不信任客户端数据 |
这个表看起来简单,但每一条背后都对应一套完整的排查流程。突发事件时,把它打印出来贴在工位上,可以让新人也能快速找到方向。
6.2 实操中容易踩的坑
这些年处理应急事件,我踩过不少坑,也见过别人踩坑。挑几个典型的说一下。
第一个坑:一上来就把服务器重启。有些同事看到CPU跑满第一反应是重启,结果攻击是停了,但日志、进程、内存数据全没了,攻击者植入的后门也一起“消失”了——不是真消失,是磁盘上的驻留还在,重启后又会自动拉起。应该先做取证,再做处置。
第二个坑:只封IP,不封攻击模式。攻击者不可能只用一个IP。你封了第一批IP,他换个代理池又打过来了。所以封IP只是临时手段,关键是识别攻击模式,用WAF规则或风控策略去拦截,而不是一个个追着封。
第三个坑:把WAF的防护规则开得太激进,把正常用户也误伤了。尤其是APP的灰度发布阶段,部分用户的IP段刚好被某个规则命中,导致大量正常请求被拦截,投诉比攻击还多。应急时拦截规则要精确,宁可先拦截,但要有快速放行和误杀恢复机制。
第四个坑:忽略数据库侧的排查。很多人只盯着应用服务器的日志,忽略了数据库的慢查询日志和错误日志。SQL注入往往会在数据库侧留下痕迹,比如大量异常查询、大量失败连接、数据表被非预期访问。应急的时候,数据库的审计日志一定要看,里面往往藏着攻击者最核心的行踪。
6.3 写在最后的话
每次处理完一次攻击事件,我都会跟团队说:这不算坏事。一次完整的应急响应,能暴露出平时测试发现不了的问题——你的监控漏了哪些指标、你的预案有没有过时、你的团队协作有没有卡点。这些问题的价值,比一万行测试用例还高。
我个人在实战中最深的体会是:攻击不可避免,但失控可以避免。你无法保证APP没有任何漏洞,但你可以保证在攻击发生的那一刻,有人知道该做什么、先做什么、不做什么。这一套流程跑顺了,你的系统就会从“被打一次修一次”变成“被打一次免疫一次”。希望这篇指南能在关键时刻帮到你——愿你永远用不上,但需要用的时候,手里有方案。