常见攻击与防护:XSS、CSRF、DDoS 与中间人
上一篇我们讲了加密、签名、TLS——把数据保护得密不透风。但真实世界里的攻击者,大多数时候根本不去硬碰密码学。他们更聪明:你把数据加密了,那我就去骗你的浏览器执行我的脚本;你用 Cookie 维持登录态,那我就诱导你的浏览器替我发请求;你服务器算力有限,那我就用海量流量把它压垮;你和服务器之间没做好认证,那我就坐到你们中间偷听篡改。
这就是 XSS、CSRF、DDoS、中间人攻击之所以经典的原因——它们分别瞄准了系统不同层面的薄弱点。很多人学安全只会背定义,结果遇到真实问题时一脸茫然,因为他不知道这一次攻击到底打在哪一层、该把防护布在哪一层。
所以这一篇我们换个顺序:先把每种攻击的运转机制拆开——攻击者具体怎么注入、怎么诱导、怎么消耗、怎么插入——看清楚"它到底是怎么得手的",再谈对应的防护应该布在哪里、为什么这么布。
一、先给四种攻击定位:它们各打哪一层
在拆细节前,先建一张地图,后面所有内容都挂在它上面:
| 攻击 | 打击目标 | 核心手法 | 主战场 |
|---|---|---|---|
| XSS | 浏览器执行环境 | 注入并执行恶意脚本 | 前端输出 / 浏览器 |
| CSRF | 会话凭据 | 盗用浏览器自动携带的登录态 | 会话机制 / 请求认证 |
| DDoS | 资源容量 | 海量请求耗尽资源 | 流量 / 接入层 |
| 中间人 | 通信链路 | 插入通信路径偷听篡改 | 传输层 / TLS |
安全防护最怕的不是不会背概念,而是不知道攻击到底打在系统的哪一层。四种攻击命中的层次完全不同,所以防护手段也完全不能互相替代。
二、XSS 的机制:让浏览器替攻击者执行脚本
XSS(跨站脚本)的核心是一句话:攻击者把恶意 JavaScript 注入到受害页面里,让浏览器在受信任的上下文中执行它。
它利用的是浏览器一个朴素的信任假设——来自当前页面的脚本默认是可信的。一旦攻击者的脚本被当成"页面自己的脚本"执行,它就拥有了页面的全部权限:能读 Cookie、能读 localStorage、能操作 DOM、能以用户身份发请求。
按注入方式,XSS 分三类,机制各异:
- 存储型:恶意脚本被存进数据库(比如发一条评论
<script>steal()</script>),之后每个浏览该页面的用户都会中招。危害最大,因为它持久且影响面广。 - 反射型:脚本藏在 URL 参数里,服务端未经处理就把它"反射"回页面。攻击者得诱导受害者点一个精心构造的链接才生效。
- DOM 型:纯前端漏洞,JS 直接把不可信数据(如
location.hash)写进 DOM(innerHTML),根本没经过服务端。
看清机制后,防护点就自然落在"切断脚本被执行"这条链上:
- 输出编码(最关键):把数据渲染到页面时,对
<>"&等做 HTML 转义,让<script>变成无害的文本字符串,浏览器就不会把它当标签执行。注意重点是输出时编码而非只在输入时过滤——同一份数据进到 HTML、属性、JS、URL 等不同位置,编码方式还不一样。 - CSP(内容安全策略):通过响应头
Content-Security-Policy告诉浏览器"只许执行来自这些来源的脚本,禁止内联脚本"。即便攻击者注入成功,脚本也会被浏览器拒绝执行——这是一道纵深防御。 - HttpOnly Cookie:给 Cookie 加
HttpOnly,JS 就读不到它。即便 XSS 得手,也偷不走会话 Cookie。
XSS 的命门在"浏览器把注入的内容当成可执行脚本"。所以防护的核心不是堵住所有输入,而是确保数据在输出到页面那一刻被正确编码,让它永远只能是数据、不会变成代码。
三、CSRF 的机制:盗用浏览器自动携带的登录态
CSRF(跨站请求伪造)常和 XSS 混淆,但机制完全不同。它不注入任何脚本,它利用的是浏览器另一个特性:向某个域名发请求时,浏览器会自动带上该域名下的 Cookie,包括登录态。
攻击链是这样的:
- 你登录了银行网站
bank.com,浏览器存了你的会话 Cookie; - 你没退出,又去逛了攻击者的网站
evil.com; evil.com页面里藏了一段代码,比如一个自动提交的表单或一张图片:<img src="https://bank.com/transfer?to=hacker&amount=10000">;- 你的浏览器加载这个资源时,会自动带上
bank.com的 Cookie 发出这个转账请求; bank.com服务端一看 Cookie 有效,以为是你本人操作,就执行了转账。
CSRF 的命门是"请求是你的浏览器发的、带着你的登录态,但并不是你本意想发的"。服务端无法仅凭 Cookie 区分"用户主动操作"和"被第三方页面诱导发出"。
防护点因此落在"让服务端能验证这个请求确实来自本站、出于用户本意":
- CSRF Token:服务端给每个表单/会话发一个随机 token,藏在页面里。合法请求会带上它,而
evil.com拿不到这个 token(受同源策略限制读不到bank.com页面内容),伪造的请求自然缺这个值,服务端一验就拦下。 - SameSite Cookie:给 Cookie 设
SameSite=Lax或Strict,浏览器在跨站请求时就不自动带这个 Cookie 了。这等于从源头切断了 CSRF 的燃料,是现代浏览器的主力防线。 - 校验 Origin / Referer 头:服务端检查请求来源域名是否是本站。
四、XSS 与 CSRF 的本质区别
这两个太容易混,单独点破:
- XSS 是"代码注入":攻击者的脚本跑在你的页面里,能读能写,本质是拿到了你页面的执行权限。CSRF Token 防不住 XSS——因为脚本就在页面内,能直接把 token 读出来。
- CSRF 是"请求伪造":攻击者看不到你的页面内容、读不到响应,他只是"盲发"一个带着你 Cookie 的请求,赌服务端会执行。
一句话记牢:XSS 是"别人的代码在你的页面里运行",CSRF 是"你的浏览器替别人发了请求"。前者攻破执行环境,后者滥用会话凭据。所以 XSS 危害更大——攻破 XSS 往往意味着 CSRF 防护也一起失效。
五、DDoS 的机制:耗尽某一种资源
DDoS(分布式拒绝服务)和前两者完全不同——它不偷数据,目标是让服务无法正常响应真实用户。它的手法是用海量请求耗尽某种有限资源。关键在于看清它到底在耗哪种资源,因为不同打法耗的东西不一样:
- 网络带宽(容量型):如 UDP 反射放大攻击,攻击者伪造受害者 IP 向某些服务(DNS、NTP)发小请求,让它们把几十倍大的响应全砸向受害者,直接打满入口带宽。
- 连接表 / 内核资源(协议型):经典的 SYN 洪泛——攻击者发大量 SYN 但不完成三次握手的第三步,服务端为每个半开连接分配资源、塞满半连接队列,正常用户再也握不上手。(这正好呼应前面讲的 TCP 三次握手机制:攻击者就是卡在第二步之后不回 ACK。)
- 应用层资源(应用型):如 HTTP 洪泛,专挑消耗大的接口(复杂查询、大文件)狂打,耗尽 CPU、数据库连接、业务线程池。这种最难防,因为请求看起来都"合法"。
防护因此也必须对症下药、分层布置:
- 容量型 → 靠流量清洗和上游带宽(云厂商的高防 IP、CDN 把流量扛在边缘);
- 协议型 → 靠 SYN Cookie(不立即分配资源,用算法验证后再建连)、连接限速;
- 应用型 → 靠 限流(rate limiting)、人机验证、WAF 规则、业务降级。
DDoS 防护的第一步永远是"判断它在耗尽哪种资源——带宽、连接表、CPU 还是业务逻辑"。说不清耗的是哪一层,就堆不对防护手段。一句"上个高防"未必拦得住应用层慢攻击。
六、中间人攻击的机制:坐到通信链路中间
中间人攻击(MITM)的核心是位置:攻击者插到通信双方的链路中间,让流量都经过他。这样他既能偷看,也能篡改,而双方可能毫无察觉。
常见手法包括 ARP 欺骗(在局域网里冒充网关)、DNS 劫持(把域名解析到攻击者的 IP)、伪造 WiFi 热点等。一旦流量过他的手:
- 明文传输(HTTP)→ 内容全裸,账号密码一览无余;
- 没做证书校验的"加密"→ 攻击者可以给双方各递一把自己的假公钥,分别和两边建立加密连接,中间转发时解密偷看再重新加密。双方都以为在安全通信,其实中间隔了个人。
这恰好解释了上一篇为什么强调 TLS 的证书验证如此关键:
- TLS 用证书证明"对面公钥确实属于这个域名",由可信 CA 背书。攻击者递的假公钥没有合法 CA 签名,浏览器验证证书时就会失败报警;
- 所以真正能挡住中间人的,不是"加密"本身,而是"加密 + 严格的身份认证"。只加密不认证,照样会把数据安全地发给中间人。
中间人攻击之所以危险,是因为受害者意识不到自己在和攻击者对话。能破解它的唯一办法,是有一套可靠的身份认证机制(证书)让冒充者无法通过验证——这正是 HTTPS 证书校验存在的根本理由,绝非形式主义。
防护:全站强制 HTTPS、开启 HSTS(强制浏览器只用 HTTPS 访问,杜绝降级)、严格校验证书、敏感场景用证书钉扎(pinning)。
七、回到设计:为什么防护必须分层
把四种攻击的机制并排看,一个结论非常清楚:它们打在不同的层,所以防护也必须分布在不同的层,没有一招通吃。
- XSS → 前端输出编码 + CSP + HttpOnly,战场在浏览器执行环境;
- CSRF → SameSite Cookie + CSRF Token + 校验 Origin,战场在会话与请求认证;
- DDoS → 流量清洗 + 限速 + WAF,战场在接入层和资源容量;
- 中间人 → 强制 HTTPS + HSTS + 证书校验,战场在传输链路。
只会喊一句"加个 WAF"或"上了 HTTPS 就安全",往往远远不够——WAF 拦不住 CSRF 的合法格式请求,HTTPS 也防不住 XSS 注入。防护的有效性,取决于它和攻击命中的层是否对得上。
八、对后端开发者最重要的启发
不要把安全当成上线前最后一天补的清单。回看这四种攻击,绝大多数缺口其实来自很基础的设计选择:
- Cookie 有没有设
HttpOnly+Secure+SameSite?(一行配置,同时削弱 XSS 窃取和 CSRF) - 模板渲染时输出有没有自动转义?(框架默认开,但
v-html、dangerouslySetInnerHTML、innerHTML这些"逃生舱"是 XSS 重灾区) - 写操作接口有没有做权限校验和幂等?(别指望前端隐藏按钮就安全,攻击者直接打接口)
- 接入层有没有强制 HTTPS、配 HSTS?
- 关键接口有没有限流和异常流量监控?
安全不是额外功能,而是系统设计的一部分。绝大多数线上安全事故,根源都是某个"图省事"的基础设计选择,而不是攻击者用了什么高深手段。
学习这一部分最容易踩的坑
1. 把 XSS 和 CSRF 搞混
XSS 是"别人的脚本在你页面里运行"(代码注入,能读能写),CSRF 是"你的浏览器替别人发请求"(盗用会话,盲发)。防护手段完全不同:CSRF Token 防不了 XSS,因为脚本能直接读走 token。
2. 以为 HTTPS 能防 XSS / CSRF
HTTPS 保护的是传输链路(防中间人偷看篡改),它对 XSS(浏览器内执行)和 CSRF(会话滥用)毫无作用。加密的请求一样可以是被诱导发出的、页面一样可以被注入脚本。层不对,防护就无效。
3. 以为防 DDoS 就是"扩容 + 上高防"
容量型攻击靠带宽和清洗能扛,但应用层慢攻击(专打高消耗接口)扩容反而是给攻击者送资源。防 DDoS 的前提是先判断它在耗尽哪种资源,再对症下药。
4. 只在输入时过滤 XSS,不在输出时编码
同一份数据输出到 HTML 标签、HTML 属性、JS、URL 时,安全的编码方式各不相同。只在输入处做一刀切过滤,既可能漏掉某些上下文,又可能误伤正常内容。正确做法是按输出位置做对应编码。
总结
这一篇我们坚持先讲攻击机制、再谈分层防护,核心要带走的是"攻击打哪一层、防护就布哪一层"这条判断力:
- XSS 攻破浏览器执行环境(注入脚本),防护靠输出编码 + CSP + HttpOnly;
- CSRF 盗用浏览器自动携带的会话凭据(盲发请求),防护靠 SameSite + CSRF Token + 校验 Origin;
- XSS 是代码注入(能读写)、CSRF 是请求伪造(看不到响应),二者本质不同、不可互相替代;
- DDoS 耗尽某种资源,关键是判断耗的是带宽、连接表还是 CPU,再分层用清洗/SYN Cookie/限流应对;
- 中间人坐在链路中间偷听篡改,唯一可靠的破解是"加密 + 严格证书认证",这正是 HTTPS 证书校验的意义;
- 防护必须分层,没有一招通吃;绝大多数事故源于基础设计选择,安全应内建于设计而非事后补丁。
当你看到一种攻击,能立刻判断它打在哪一层、防护该布在哪一层,而不是背一堆孤立定义,这部分就真正属于你了。
参考资源: