常见攻击与防护: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,包括登录态。

攻击链是这样的:

  1. 你登录了银行网站 bank.com,浏览器存了你的会话 Cookie;
  2. 你没退出,又去逛了攻击者的网站 evil.com
  3. evil.com 页面里藏了一段代码,比如一个自动提交的表单或一张图片:<img src="https://bank.com/transfer?to=hacker&amount=10000">
  4. 你的浏览器加载这个资源时,会自动带上 bank.com 的 Cookie 发出这个转账请求;
  5. bank.com 服务端一看 Cookie 有效,以为是你本人操作,就执行了转账。

CSRF 的命门是"请求是你的浏览器发的、带着你的登录态,但并不是你本意想发的"。服务端无法仅凭 Cookie 区分"用户主动操作"和"被第三方页面诱导发出"。

防护点因此落在"让服务端能验证这个请求确实来自本站、出于用户本意":

  • CSRF Token:服务端给每个表单/会话发一个随机 token,藏在页面里。合法请求会带上它,而 evil.com 拿不到这个 token(受同源策略限制读不到 bank.com 页面内容),伪造的请求自然缺这个值,服务端一验就拦下。
  • SameSite Cookie:给 Cookie 设 SameSite=LaxStrict,浏览器在跨站请求时就不自动带这个 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-htmldangerouslySetInnerHTMLinnerHTML 这些"逃生舱"是 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 证书校验的意义;
  • 防护必须分层,没有一招通吃;绝大多数事故源于基础设计选择,安全应内建于设计而非事后补丁。

当你看到一种攻击,能立刻判断它打在哪一层、防护该布在哪一层,而不是背一堆孤立定义,这部分就真正属于你了。

参考资源