一、CSRF 是什么?
CSRF 的全称是 Cross-Site Request Forgery,中文通常译为 跨站请求伪造。
它指的是攻击者利用用户已经登录某个网站的状态,让用户的浏览器在不知情的情况下,向目标网站发送一个“看起来像本人操作”的请求。
举个例子:
用户已经登录了某个购物网站。
攻击者诱导用户打开一个恶意网页。
恶意网页自动向购物网站发送修改收货地址的请求。
浏览器自动带上购物网站的登录 Cookie。
购物网站以为这是用户本人提交的操作。
收货地址被改成攻击者指定的地址。
整个过程中,攻击者不一定知道用户密码,也不一定能直接读取用户 Cookie。它利用的是浏览器会自动携带登录状态这一机制。
CSRF 的危险点在于:用户只是打开了一个页面,目标网站却可能已经执行了某个操作。
二、CSRF 为什么能发生?
很多网站依赖 Cookie 维持登录状态。
用户登录网站后,服务器会给浏览器设置一个登录 Cookie。之后用户再访问这个网站时,浏览器会自动携带 Cookie,服务器就能识别用户身份。
这套机制让登录体验变得方便。问题也随之出现:当第三方网页诱导浏览器向目标网站发送请求时,浏览器也可能自动带上对应网站的 Cookie。
攻击者利用的正是这一点。
CSRF 的关键条件通常有三个:
| 条件 | 说明 |
|---|---|
| 用户已经登录目标网站 | 浏览器里存在有效 Cookie |
| 目标网站只依赖 Cookie 判断身份 | 请求本身缺少额外校验 |
| 攻击者能诱导用户访问恶意页面 | 恶意页面自动触发请求 |
满足这些条件后,攻击者就可能让用户的浏览器代替用户执行操作。
三、一个简单的 CSRF 攻击示例
假设某个网站有一个修改邮箱的接口:
POST https://example.com/account/change-email
正常情况下,用户会在网站设置页面输入新邮箱,然后点击保存。
如果这个接口只检查用户是否登录,没有检查请求来源,也没有 CSRF Token,攻击者就可能构造一个恶意页面:
<form action="https://example.com/account/change-email" method="POST">
<input type="hidden" name="email" value="[email protected]">
</form>
<script>
document.forms[0].submit();
</script>
用户已经登录 example.com 的情况下,再打开这个恶意页面,浏览器可能会自动提交表单。请求发出时,浏览器会带上 example.com 的登录 Cookie。
目标网站收到请求后,只看到“这是一个已登录用户提交的修改邮箱请求”。邮箱就可能被改掉。
这就是 CSRF 的典型攻击路径。
四、CSRF 能造成什么后果?
CSRF 的影响取决于目标网站允许用户执行哪些操作。
| 场景 | 可能后果 |
|---|---|
| 个人资料网站 | 修改邮箱、手机号、头像、昵称 |
| 社交平台 | 自动关注、点赞、发帖、发送私信 |
| 电商网站 | 修改收货地址、提交订单、取消订单 |
| 金融平台 | 发起转账、修改收款账户、购买产品 |
| 企业后台 | 删除数据、修改权限、创建新账号 |
| 云服务平台 | 创建资源、关闭服务、修改安全组 |
| 内容管理系统 | 删除文章、修改页面、发布恶意内容 |
对普通用户来说,CSRF 可能带来账号风险和财产损失。
对企业来说,CSRF 可能影响后台管理系统、客户数据、业务系统和云资源安全。
权限越高,CSRF 的破坏力越大。管理员账号被 CSRF 利用时,后果通常比普通用户更严重。
五、CSRF 和 XSS 有什么区别?
CSRF 和 XSS 都是常见 Web 安全问题,但攻击方式不同。
| 对比项 | CSRF | XSS |
|---|---|---|
| 中文名 | 跨站请求伪造 | 跨站脚本攻击 |
| 攻击核心 | 借用用户登录状态发送请求 | 在网页中执行恶意脚本 |
| 是否需要读取 Cookie | 通常不需要 | 可能尝试读取 Cookie 或页面数据 |
| 是否需要目标页面存在脚本注入 | 通常不需要 | 需要 |
| 常见结果 | 代替用户执行操作 | 窃取信息、劫持页面、发起操作 |
| 防护重点 | Token、SameSite、Origin 校验 | 输入过滤、输出转义、CSP |
CSRF 更像是“借用户身份发请求”。
XSS 更像是“把恶意脚本放进网页里运行”。
两者也可能组合出现。攻击者通过 XSS 获取页面中的 Token,再进一步绕过 CSRF 防护。因此,Web 安全不能只修一个点。
六、哪些接口最容易出现 CSRF 风险?
CSRF 常见于会改变用户状态的接口。
例如:
| 高风险接口 | 风险说明 |
|---|---|
| 修改邮箱 | 攻击者可能接管后续找回密码流程 |
| 修改密码 | 攻击者可能直接控制账号 |
| 绑定手机号 | 攻击者可能替换安全验证方式 |
| 转账付款 | 直接造成资金损失 |
| 修改收货地址 | 电商订单可能被劫持 |
| 删除数据 | 影响业务和用户资产 |
| 管理员操作 | 权限变化可能造成系统级风险 |
特别需要注意的是:敏感操作不应该使用 GET 请求完成。
错误示例:
GET /delete-account
GET /transfer?to=attacker&amount=1000
GET /admin/delete-user?id=123
GET 请求适合读取数据。修改、删除、转账、提交订单、变更权限这类操作,应该使用 POST、PUT、PATCH 或 DELETE,并配合服务端校验。
七、开发者如何防范 CSRF?
1. 使用 CSRF Token
CSRF Token 是最常见、最基础的防护手段。
服务器为用户生成一个随机 Token,并把它放入页面或响应中。用户提交表单或发送请求时,必须同时携带这个 Token。服务器收到请求后,检查 Token 是否正确。
攻击者可以诱导浏览器发送请求,但通常拿不到页面里的 Token,因此伪造请求会被拦截。
示例:
<form method="POST" action="/account/change-email">
<input type="hidden" name="csrf_token" value="random_token_here">
<input type="email" name="email">
<button type="submit">保存</button>
</form>
服务端校验示例:
if (request.body.csrf_token !== session.csrf_token) {
return response.status(403).send("Invalid CSRF token");
}
CSRF Token 应符合几个要求:
| 要求 | 说明 |
|---|---|
| 足够随机 | 避免被猜出 |
| 与用户会话绑定 | 不能所有用户共用一个 Token |
| 不放在 URL 中 | 避免被浏览器历史、日志、Referer 暴露 |
| 敏感操作必须校验 | 不能只保护部分表单 |
| 有合理过期策略 | 降低长期泄露风险 |
2. 设置 SameSite Cookie
SameSite 是 Cookie 的安全属性,用来限制跨站请求时 Cookie 是否会被浏览器发送。
常见取值如下:
| SameSite 值 | 含义 |
|---|---|
| Strict | 只有同站请求才发送 Cookie |
| Lax | 大多数跨站子请求不发送 Cookie,部分顶级跳转允许 |
| None | 跨站请求也发送 Cookie,必须配合 Secure |
常见配置:
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Lax
安全要求更高的后台系统可以考虑:
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Strict
SameSite=Lax 适合大多数常规网站。
SameSite=Strict 安全性更强,但可能影响跨站登录、支付回调和第三方跳转体验。
3. 校验 Origin 和 Referer
服务器可以检查请求头中的 Origin 或 Referer,判断请求是否来自可信域名。
例如,只允许来自本站的请求:
Origin: https://example.com
服务端示例:
const allowedOrigin = "https://example.com";
if (request.headers.origin !== allowedOrigin) {
return response.status(403).send("Invalid origin");
}
Origin 校验适合保护 POST、PUT、PATCH、DELETE 等请求。
Referer 可以作为补充,但它可能受到浏览器隐私策略、插件或代理环境影响。
365VPN 安全团队建议采用组合防护:CSRF Token + SameSite Cookie + Origin 校验。单一措施更容易受到业务场景和浏览器行为影响。
4. 敏感操作加入二次验证
高风险操作需要额外确认。
| 操作 | 推荐验证方式 |
|---|---|
| 修改密码 | 输入旧密码 |
| 修改邮箱 | 邮箱验证码 |
| 修改手机号 | 短信或认证器验证 |
| 转账付款 | 交易密码、MFA、设备确认 |
| 删除账号 | 重新登录 |
| 修改管理员权限 | 管理员二次确认 |
| 导出敏感数据 | MFA 或审批流程 |
二次验证可以降低 CSRF 成功后的损害范围。即使攻击者成功发起请求,关键操作也需要用户完成额外验证。
5. 禁止用 GET 请求执行敏感操作
GET 请求常被浏览器、搜索引擎、聊天软件预览、邮件客户端自动访问。用 GET 执行敏感操作,会让风险显著增加。
错误做法:
GET /user/delete?id=123
推荐做法:
POST /user/delete
并配合:
CSRF Token
SameSite Cookie
Origin 校验
权限校验
二次确认
状态改变类接口需要被视为高风险接口处理。
6. 启用框架内置 CSRF 防护
现代 Web 框架通常已经提供 CSRF 防护能力。
| 框架 | 常见防护机制 |
|---|---|
| Django | CSRF Middleware |
| Rails | authenticity_token |
| Laravel | CSRF Token Middleware |
| Spring Security | CSRF Protection |
| ASP.NET Core | Anti-forgery Token |
| Express.js | csurf 等中间件 |
开发者应优先启用框架内置机制,再根据业务情况补充 SameSite、Origin 校验、MFA 和权限控制。
八、前后端分离项目还需要防 CSRF 吗?
需要根据认证方式判断。
使用 Cookie 认证
前后端分离项目如果使用 Cookie 保存登录态,仍然需要防范 CSRF。
建议配置:
| 措施 | 作用 |
|---|---|
| SameSite=Lax 或 Strict | 降低跨站自动带 Cookie 的概率 |
| CSRF Token | 校验请求是否来自可信页面 |
| Origin 校验 | 阻止未知来源请求 |
| CORS 白名单 | 限制跨域访问 |
| 敏感接口不用 GET | 防止链接触发操作 |
使用 Authorization Header
如果前端使用 Authorization: Bearer 请求头传递 Token,浏览器通常不会在跨站请求中自动附带这个 Header,传统 CSRF 风险会降低。
示例:
Authorization: Bearer eyJhbGciOi...
但这类方案需要重点防范 XSS 和 Token 泄露。Token 放在 LocalStorage、SessionStorage 或前端内存中,各有安全取舍。
Cookie 认证更关注 CSRF。
Bearer Token 更关注 XSS 和存储安全。
开发者需要根据项目结构设计防护方案。
九、普通用户能做什么?
CSRF 的主要责任在网站开发者,但普通用户也可以降低被攻击概率。
| 建议 | 作用 |
|---|---|
| 不随便点击陌生链接 | 减少进入恶意页面的机会 |
| 重要账户开启双重验证 | 降低高风险操作被直接执行的概率 |
| 及时更新浏览器 | 获得 SameSite 等安全机制支持 |
| 避免安装来路不明插件 | 插件可能读取页面或篡改请求 |
| 操作完重要账户后退出登录 | 降低长期登录态被利用的机会 |
| 不在陌生网页输入敏感信息 | 降低钓鱼和账号泄露风险 |
| 使用公共 Wi-Fi 时开启 VPN | 降低网络侧窃听和劫持风险 |
365VPN 可以帮助用户在公共 Wi-Fi、酒店网络、机场网络、咖啡馆网络中建立加密隧道,降低本地网络窃听、DNS 劫持和中间人攻击风险。
需要明确的是,VPN 不能直接修复网站自身的 CSRF 漏洞。CSRF 发生在浏览器登录态和目标网站请求校验之间。VPN 的价值在于保护网络连接层,减少不可信网络环境带来的额外安全风险。
十、VPN 能防止 CSRF 吗?
VPN 不能直接防止 CSRF。
CSRF 的核心是攻击者借用用户的浏览器和登录态发起请求。只要用户已经登录目标网站,并打开了恶意页面,伪造请求仍可能从用户浏览器发出。VPN 无法替网站检查 CSRF Token,也无法判断一次请求是否由用户主动触发。
但 VPN 能保护另一层安全问题。
| 风险类型 | VPN 是否有帮助 |
|---|---|
| 公共 Wi-Fi 窃听 | 有帮助 |
| DNS 劫持 | 有帮助 |
| 本地网络追踪 | 有帮助 |
| 隐藏真实 IP | 有帮助 |
| 中间人攻击风险 | 有帮助 |
| 网站自身 CSRF 漏洞 | 无法直接修复 |
| 浏览器执行恶意页面 | 无法直接阻止 |
| 用户登录态被滥用 | 无法直接阻止 |
365VPN 的作用是提供加密连接、保护公共网络环境、降低真实 IP 暴露,并帮助用户更安全地访问海外网站和服务。CSRF 防护仍然需要网站开发者在服务端实现。
十一、常见 CSRF 防护误区
误区一:用了 HTTPS 就不会有 CSRF
HTTPS 保护传输过程,防止数据在网络中被窃听或篡改。
CSRF 利用的是浏览器自动携带登录态发请求。
HTTPS 很重要,但它不能替代 CSRF Token。
误区二:接口用 POST 就安全
POST 更适合提交和修改数据,但攻击者仍然可以构造自动提交的 POST 表单。
POST 接口仍然需要 Token、SameSite 和 Origin 校验。
误区三:只检查 Referer 就够了
Referer 可以辅助判断请求来源,但可能被隐藏、裁剪或受到浏览器隐私策略影响。
更稳妥的做法是同时使用 CSRF Token 和 Origin 校验。
误区四:前后端分离项目没有 CSRF
只要认证依赖 Cookie,前后端分离项目也可能存在 CSRF。
API 项目仍然要根据认证方式设计防护策略。
误区五:验证码可以替代 CSRF Token
验证码适合对抗自动化滥用。
CSRF Token 适合校验请求来源和会话绑定。
两者解决的问题不同。验证码不能替代基础 CSRF 防护。
十二、CSRF 防护检查清单
开发者可以用下面这份清单检查项目安全性。
| 检查项 | 建议 |
|---|---|
| 所有敏感操作使用 POST / PUT / PATCH / DELETE | 必须 |
| 敏感接口启用 CSRF Token | 必须 |
| Session Cookie 设置 HttpOnly | 必须 |
| Session Cookie 设置 Secure | 必须 |
| Session Cookie 设置 SameSite=Lax 或 Strict | 推荐 |
| 服务端校验 Origin | 推荐 |
| CORS 只允许可信域名 | 必须 |
| 不把 Token 放在 URL 中 | 必须 |
| 修改密码、邮箱、支付等操作加入二次验证 | 必须 |
| 管理后台单独加强保护 | 必须 |
| 框架内置 CSRF 中间件已启用 | 推荐 |
| 登录、退出、修改资料接口经过安全测试 | 必须 |
| 配合 XSS 防护,避免 Token 被脚本读取 | 必须 |
CSRF 防护需要和身份认证、权限控制、XSS 防护、Cookie 配置一起设计。只加一个 Token,无法覆盖所有业务风险。
十三、365VPN 安全团队建议
CSRF 是 Web 安全中非常基础,也非常容易被忽视的问题。它不需要攻击者破解密码,也不需要攻击者直接拿到用户 Cookie。只要网站缺少请求校验,攻击者就可能诱导用户浏览器代替用户完成操作。
对开发者来说,所有会改变状态的接口都应该纳入 CSRF 防护范围。修改资料、绑定账号、提交订单、转账支付、删除数据、管理权限,这些操作都需要 Token、SameSite、Origin 校验和权限控制。高风险操作还应加入二次验证。
对普通用户来说,保持浏览器更新、谨慎打开陌生链接、为重要账户开启双重验证,是减少风险的基础。使用公共 Wi-Fi 或跨境访问重要服务时,建议开启 365VPN,通过 AES-256 加密隧道保护网络连接,降低本地网络窃听、DNS 劫持和中间人攻击风险。
365VPN 不能替网站修复 CSRF 漏洞,但可以为用户提供更安全的网络环境。网络安全不是单一工具可以完成的事情。网站开发、浏览器机制、网络连接和用户习惯,都需要共同参与。
十四、结语
CSRF 跨站请求伪造的本质,是攻击者借用用户已经登录的身份,诱导浏览器向目标网站发送操作请求。用户可能没有点击保存,没有确认转账,也没有主动提交表单,但目标网站仍可能收到一个带有登录态的请求。
防范 CSRF 的关键,是让服务器能够分辨哪些请求来自真实用户操作,哪些请求来自第三方页面伪造。CSRF Token、SameSite Cookie、Origin 校验、权限控制和二次验证,是目前更成熟的防护组合。
365VPN 安全团队建议,开发者在产品设计阶段就把 CSRF 纳入基础安全检查;普通用户在访问重要账户、使用公共 Wi-Fi、跨境访问海外网站时,也应配合现代浏览器、双重验证和 VPN 加密连接,减少网络环境带来的额外安全风险。
