当前位置: 首页 > news >正文

关于 Web 漏洞原理与利用:3. CSRF(跨站请求伪造)

一、原理:

利用用户登录态伪造操作

CSRF(Cross-Site Request Forgery,跨站请求伪造)是攻击者“借刀杀人”,借用用户浏览器中已有的登录状态,诱导用户完成攻击者指定的操作。

1. 基本机制分解

1)浏览器的默认行为:自动带上 Cookie(包括 sessionid)

当你访问一个网站并登录后,例如:

POST /login
Host: bank.com
Cookie: sessionid=abc123
  • 网站会通过 Cookie(如 sessionid)记录你的登录状态。

  • 登录后,每次你再访问这个网站,浏览器都会自动带上 Cookie

GET /user/profile
Cookie: sessionid=abc123

这是 浏览器的默认行为,不管你怎么发请求,只要是访问 bank.com,就自动带上它的 Cookie。

2)网站服务器的判断逻辑

网站一般只根据 Cookie 判断用户身份

if request.cookie["sessionid"] is valid:allow_operation()

所以请求 只要带了合法的 Cookie,网站就以为是“你自己操作的”。

3)攻击者不能获取 Cookie,但能让浏览器代发请求

攻击者 无法直接读取你的 Cookie,但却可以通过诱导你访问恶意页面,让浏览器替他发出请求
浏览器会在请求中 自动附带 Cookie,即使这是攻击者构造的请求!

攻击者只需要这样:

<img src="https://bank.com/transfer?to=attacker&amount=10000">

当你一打开这个网页:

  • 浏览器会访问 bank.com

  • 自动附带你的 Cookie(如 sessionid);

  • 请求落到银行服务器上;

  • 银行服务器识别 Cookie 合法,就执行了“转账”。

结果是:你替攻击者完成了操作,自己还一无所知。

2. 类比解释:伪造你发指令

想象这个场景:

  • 你在一个公司门禁系统中,登录了一个可以发指令的管理后台;

  • 攻击者不能进公司,但可以给你发一个“点击这个链接”的诱导邮件;

  • 你一不小心点开,就自动触发了一个“给他打钱”的命令;

  • 门禁系统看到是你发的,指令合法,就执行了。

攻击者没权限,但他“骗你”用你的权限帮他做了事。

3. 条件总结(CSRF 成功的关键前提)

  1.  用户已登录目标网站,且登录状态仍有效(Cookie 存在);

  2.  目标网站通过 Cookie 识别身份(常见);

  3.  请求没有额外校验(如 CSRF token);

  4.  攻击者诱导用户访问了恶意链接或页面;

  5.  浏览器自动发送 Cookie,服务器误以为是用户行为。

4. 攻击流程图(逻辑顺序)

[用户登录 bank.com] → [获得 sessionid Cookie]↓
[访问恶意网站] → [构造对 bank.com 的请求]↓
[浏览器自动带上 sessionid]↓
[bank.com 收到请求] → [识别为用户操作] → 执行了操作

5. 攻击者和用户的角色区别

项目用户攻击者
拥有 Cookie 是 否
能发请求 是 能骗用户发
能伪造内容 无法伪造 Cookie,但能伪造请求内容
能操作目标站(自己操作)(借助用户操作)

总结

CSRF 利用的不是系统漏洞,而是 Web 的信任机制 + 用户不知情行为 + 浏览器的自动 Cookie 行为。


二、构造:

自动提交表单

攻击者构造一个伪造的表单,提前填好表单字段,让用户在访问时自动提交,借此触发目标网站上的敏感操作(如转账、修改密码等)。

1. 构造基本结构

<form action="https://bank.com/transfer" method="POST"><input type="hidden" name="to" value="attacker123"><input type="hidden" name="amount" value="10000">
</form><script>document.forms[0].submit(); // 页面加载后自动提交表单
</script>

2. 构造流程详解

1)<form> 标签构建 POST 请求

<form action="https://bank.com/transfer" method="POST">
  • action 是目标地址;

  • method="POST" 表示发起 POST 请求;

  • 请求将带上表单中的参数。

2)使用隐藏字段构造参数

<input type="hidden" name="to" value="attacker123">
<input type="hidden" name="amount" value="10000">
  • 这些字段用户看不到;

  • 但它们会作为 POST 的参数发送出去;

  • 模拟的是用户提交表单的过程。

3)使用 JavaScript 自动提交表单

document.forms[0].submit();
  • 页面加载时立即提交;

  • 用户根本无感知。

3. 构造后发出的请求(抓包效果)

POST /transfer HTTP/1.1
Host: bank.com
Content-Type: application/x-www-form-urlencoded
Cookie: sessionid=abcdef123456to=attacker123&amount=10000

浏览器自动带上用户登录状态中的 Cookie(如 sessionid),服务器误以为是用户自己发出的请求。

4. 实战演示用法(真实攻击逻辑)

假设:

目标网站 bank.com 有如下逻辑:

  • POST /transfer 可以转账;

  • 需要参数 toamount

  • 只要 Cookie 中的 session 合法就执行操作;

  • 没有 CSRF Token 或 Referer 校验

攻击页面代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>你中奖了</title>
</head>
<body><h1>恭喜你中奖了!正在处理领奖信息...</h1><form id="csrfForm" action="http://localhost:8000/transfer" method="POST"><input type="hidden" name="to" value="attacker_account"><input type="hidden" name="amount" value="10000"></form><script>window.onload = function() {document.getElementById('csrfForm').submit();}</script>
</body>
</html>

攻击流程:

  • 用户在登录了 bank.com 后,未退出;

  • 用户访问了攻击者构造的钓鱼网页;

  • 浏览器在加载页面时,自动提交表单;

  • bank.com 收到合法 Cookie + 合法参数;

  • 成功执行“给攻击者转账”操作。

5. 关键点

特性描述
请求类型POST
参数构造方式隐藏字段 <input type="hidden">
自动触发方式JS:form.submit()
浏览器行为自动携带 Cookie
用户感知程度无感知,访问页面即中招

6. 限制与防御

这种方式虽然常见,但也容易被防御:

防御方式是否能阻止这种攻击
CSRF Token 校验 可以阻止
Referer 校验 可以阻止
SameSite Cookie 限制 可以阻止
登出机制不当 无法阻止
用户粗心点开链接 攻击成功

总结

自动提交表单是构造 CSRF 的最主流手段,它依赖浏览器自动携带 Cookie + 用户无感知行为,在攻击页面中用隐藏字段 + JS 一键触发操作。

=======================================

img/src 请求

<img> 标签中的 src 属性,只要被浏览器解析,就会自动发出 GET 请求

攻击者可利用这一点,构造一段带有 img 标签的 HTML 页面,诱导用户访问,让用户在不知情的情况下向目标网站发起请求。

最关键的是:浏览器在发出这个 GET 请求时,会自动携带当前域名下的 Cookie(如 sessionidtoken 等登录态信息)。

如果目标网站没有做好 CSRF 防御,攻击就可能成功。

1. 构造示例

<!-- 攻击者网页上的 HTML 代码 -->
<img src="https://bank.com/transfer?to=attacker&amount=10000">

2. 浏览器行为分析

  • 用户访问攻击者构造的网页;

  • <img> 标签被浏览器解析;

  • 浏览器自动向 https://bank.com/transfer?... 发起 GET 请求;

  • 自动带上当前用户的 Cookie(如 sessionid=abcdef123456);

  • 如果目标接口没有验证 Referer、Token,服务器会误以为是合法操作;

  • 攻击成功。

发出的请求大致

GET /transfer?to=attacker&amount=10000 HTTP/1.1
Host: bank.com
Cookie: sessionid=abcdef123456
User-Agent: Mozilla/5.0 ...

3. 攻击条件

要让攻击成功,必须满足以下条件:

条件说明
用户已登录目标网站否则没有有效 Cookie,无法伪造操作
Cookie 中记录了身份凭证如 sessionid 或 JWT
目标接口使用 GET 实现敏感操作如转账、绑定邮箱、删除内容等(极其不安全)
没有 CSRF Token 或 Referer 检查否则请求会被拦截

4. 其它类似的标签(也能触发 GET)

攻击者可以不止使用 <img>,还可以使用以下方式:

标签示例代码
<img><img src="...">
<script><script src="...">
<iframe><iframe src="...">
<link><link rel="stylesheet" href="...">
<object><object data="...">

5. img/src 的限制

限制点说明
只能发 GET 请求无法发 POST 请求
无法自定义请求头不能设置 Referer、User-Agent 等
无法处理响应JavaScript 无法获取返回内容
一旦目标接口有验证就失败CSRF Token、SameSite Cookie、Referer 限制

6. 使用场景

虽然 POST 请求一般更危险,但一些老旧或不规范的网站,可能把敏感操作写成 GET 请求,比如:

  • GET /deleteAccount?id=123

  • GET /addFriend?user=evil

  • GET /transfer?to=attacker&amount=5000

这类系统就特别容易被 <img> 标签攻击。

7. 攻击场景举例

1)删除某用户帖子:

<img src="https://forum.com/deletePost?id=999">

用户点击钓鱼链接或访问攻击页面后,该帖子被删除。

2)给攻击者点赞/加好友:

<img src="https://social.com/addFriend?uid=attacker">

用户以为自己在看图片,其实是在无意间帮攻击者加了好友。

8. 安全建议(从服务端角度)

防御措施有效性
禁止用 GET 做敏感操作 非常重要
使用 CSRF Token 推荐
检查 Referer / Origin 可选
设置 SameSite Cookie 可阻止跨站请求
用户操作需二次确认 提高安全性

总结

img/src 是最“隐蔽”的 CSRF 构造方式之一,用户根本意识不到任何操作,但背后其实可能在给别人转账、点赞、删除内容,属于“无交互感知攻击”,而浏览器的默认行为(自动发 GET、自动带 Cookie)正是它得逞的根源。


三、  防御:

Token 验证

**CSRF Token(跨站请求伪造令牌)**是一段由服务器生成、随机、不可预测的字符串,用来绑定用户请求和用户身份之间的唯一性,防止恶意网站伪造用户的请求。

它不保存在 Cookie 中,而是嵌入在 HTML 页面中,并随着每个请求一起发送回来。

为什么需要 Token?

因为 Cookie 是自动发送的,攻击者可以构造伪造请求利用用户的登录态。而 Token 是攻击者无法提前获取、又必须提交的验证参数。

所以只要验证这个 Token,服务器就能判断请求是不是由真实用户页面发起的。

1. 工作原理详解

1)用户访问页面

  • 服务器生成一个随机 Token:

    session['csrf_token'] = 'Xyz123Abc...'
    
  • 把这个 Token 插入到 HTML 页面里(常见方式是 form 隐藏字段):

    <input type="hidden" name="csrf_token" value="Xyz123Abc..." />
    

2)用户提交表单时

浏览器会将该隐藏字段和其他字段一起发送:

POST /transfer HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Cookie: sessionid=abc123to=tom&amount=1000&csrf_token=Xyz123Abc...

3)后端校验

后端取出提交的 Token 和保存在会话(session)中的 Token 进行比对:

if request.form['csrf_token'] != session['csrf_token']:return 'CSRF ATTACK DETECTED'

一致:允许操作
不一致/缺失:拦截攻击

2. 为什么能防御 CSRF?

因为:

  • 攻击者不能获取用户的 Token(它是嵌入 HTML 的,不能跨域读取);

  • 攻击者无法猜出 Token 内容(足够随机);

  • 即使攻击者构造了相同参数请求,缺了 Token 也无法通过验证。

3. 示例(完整 Flask 演示)

from flask import Flask, request, session, render_template_string, redirect
import secretsapp = Flask(__name__)
app.secret_key = 'your-secret-key'@app.route('/')
def form():# 生成随机 CSRF Tokentoken = secrets.token_hex(16)session['csrf_token'] = tokenreturn render_template_string('''<form action="/submit" method="post"><input type="text" name="to" placeholder="转账对象"><input type="text" name="amount" placeholder="金额"><input type="hidden" name="csrf_token" value="{{token}}"><input type="submit" value="提交"></form>''', token=token)@app.route('/submit', methods=['POST'])
def submit():if session.get('csrf_token') != request.form.get('csrf_token'):return "CSRF ATTACK BLOCKED"return f"已向 {request.form['to']} 转账 {request.form['amount']} 元"if __name__ == '__main__':app.run(debug=True)

4. 建议

方法描述
每个表单独立 Token提高安全性(避免 Token 重用)
Token 过期时间防止长期有效的令牌被利用
双 Token 机制Cookie + 表单同时携带,提升安全性
Ajax 请求放在自定义 Header 中,防止被 HTML form 模拟提交

注意:GET 请求无法用 Token 防御!

因为 <img><a><script> 标签都可以发 GET 请求,但无法携带 Token,所以:

  • 敏感操作必须使用 POST/PUT/DELETE 请求

  • 且要配合 Token 验证

总结

特性描述
 核心机制最强大的 CSRF 防御方式
 独立于浏览器行为不依赖 Cookie 属性
 不影响用户体验用户无感知
 实现略复杂需要页面与服务端同步 Token

=======================================

Referer 检查

Referer(原意是 Referrer,拼写错了但沿用了)是 HTTP 请求头的一部分,它记录了:

这个请求是从哪个页面跳转过来的。

例如,在网页中点击了一个链接或提交了一个表单,请求头就会带上:

Referer: https://www.bank.com/account

这个字段就告诉服务器:用户当前的请求是从 https://www.bank.com/account 页面发出来的。

1. Referer 检查的原理

核心逻辑:只允许来自本站页面发起的请求。

如果服务端发现请求的 Referer 不是自己的域名,则判定请求不是合法来源,有可能是 CSRF 攻击。

2. Referer 检查怎么实现?

以 Python Flask 为例:

from flask import request@app.route('/transfer', methods=['POST'])
def transfer():referer = request.headers.get('Referer')if referer is None or not referer.startswith("https://www.bank.com"):return "非法请求,可能是 CSRF 攻击", 403# 执行转账操作return "转账成功"

3. 攻击与防御场景对比

攻击请求(来自攻击者网站):

攻击者构造一个页面,诱导你点击按钮:

<form action="https://www.bank.com/transfer" method="POST"><input type="hidden" name="amount" value="10000"><input type="hidden" name="to" value="attacker">
</form>
<script>document.forms[0].submit()</script>

点击后浏览器发出 POST 请求:

POST /transfer HTTP/1.1
Host: www.bank.com
Referer: https://evil.com/attack.html
Cookie: session=123456

Referer 检查发现不是本域名,拦截。

正常请求(正常用户操作):

用户在 https://www.bank.com/account 页面点击“转账”,发起请求:

Referer: https://www.bank.com/account

服务器一看,是本站页面发来的,请求放行。

4. Referer 检查的优缺点

优点:

优点描述
简单不需要在页面嵌入 Token,服务器代码也很简单
快速生效服务端只需增加 Referer 检查逻辑即可
对用户透明不影响用户体验,不需要页面修改

缺点:

缺点描述
Referer 可能为空某些浏览器或隐私插件会去掉 Referer,导致误判
有些合法请求可能是跨域比如 OAuth 登录回调、第三方支付跳转,Referer 不是本站但合法
攻击者不能伪造 Referer,但可以构造没有 Referer 的请求比如通过 <img><iframe> 发起请求,浏览器可能不带 Referer
不适用于 API 接口移动端请求或者 AJAX 跨域接口可能没有 Referer,造成误判或不适用

5. 实际使用建议

Referer 检查作为 辅助防御机制 是很有价值的,但不能作为唯一防线,因为:

  • 它容易被绕过(Referer 空值、浏览器兼容性等);

  • 有时候会拦正常请求;

  • 安全级别不如 CSRF Token 或 SameSite Cookie。

6. 最佳实践

场景建议
Web 表单提交推荐使用 CSRF Token + Referer 检查双重防御
AJAX 请求建议加 CSRF Token 头部或参数验证
开放接口(如 API)不建议使用 Referer,推荐使用 OAuth / 签名机制等

总结

Referer 检查是一种基于请求来源的 CSRF 防御手段,通过验证请求的 Referer 是否来自本站,拦截非本站发起的请求。虽然简单有效,但存在兼容性和安全边界问题,建议作为 CSRF Token 的补充手段。

=======================================

SameSite Cookie

SameSite 是 Cookie 的一个属性,用来控制浏览器在“跨站请求”时是否发送这个 Cookie

它是由浏览器实现的安全策略,不依赖后端逻辑。主要用来防御跨站攻击(特别是 CSRF)。

跨站请求是什么意思?

举例说明:

  • 你在浏览 https://evil.com,这上面有一个表单偷偷向 https://bank.com/transfer 发 POST 请求。

  • 浏览器默认会携带你在 bank.com 登录时留下的 Cookie(含 session id)!

  • bank.com 后台认为你是登录用户,直接处理请求了!这就是 CSRF!

SameSite 属性有哪几种值?

SameSite 值描述是否允许跨站请求带 Cookie
Strict最严格,完全禁止 不允许任何跨站请求带 Cookie
Lax默认,兼容性好 允许 GET 请求带 Cookie,禁止 POST
None不限制 始终允许,但必须配合 Secure(即 HTTPS)

1. 各模式详细解读

1)SameSite=Strict

只允许 同站请求(用户主动点击本站链接、表单提交等),否则浏览器不会附带 Cookie

可防御所有类型的 CSRF!

缺点:

  • 用户从其他站点点击链接访问本站后,可能需要重新登录

2)SameSite=Lax

略微放宽,允许以下情况携带 Cookie:

  • 链接跳转(GET)

  • 资源加载(img、iframe)

  • 表单或脚本的 POST 不携带 Cookie(可防御 CSRF)

优点:

  • 大多数网站默认使用这个值,兼容性好;

  • 可防御大多数 CSRF(POST 被阻止)。

3)SameSite=None

这是唯一允许完全跨站请求带 Cookie的选项。

但有个前提:必须同时设置 Secure 属性,且使用 HTTPS,否则浏览器会拒绝设置 Cookie!

如果不加 Secure,Chrome 直接不保存这个 Cookie!

2. 设置示例(Flask)

@app.route("/set_cookie")
def set_cookie():resp = make_response("设置成功")# SameSite 可以设置为 'Strict' / 'Lax' / 'None'resp.set_cookie("session_id", "123456", samesite="Lax", secure=False)return resp

如果设置 SameSite=None,必须加 secure=True,并启用 HTTPS

3. SameSite 的 CSRF 防御原理

浏览器发起跨站请求(如:在恶意网站中自动提交表单):

  • 如果 SameSite=StrictLax,浏览器不会附带 session_id

  • 后端检测不到登录态,CSRF 请求失效 

4. 实际建议

场景SameSite 推荐值
普通用户站点(需防 CSRF)Lax(推荐)
管理后台系统(高安全性)Strict
第三方服务需带 CookieNone + Secure + HTTPS

5. 检查 Cookie 设置

打开浏览器控制台(F12 → Application → Cookies),可以看到:

  • Name:session_id

  • Value:xxxx

  • SameSite:Strict / Lax / None

  • Secure:是否开启

总结

SameSite 是浏览器级别的防御机制,用来让“跨站请求时 Cookie 不再自动发送”,从根源上限制 CSRF 攻击。

相关文章:

  • Python _day31
  • 第40天-Python开发音乐播放器完整指南
  • Java 10IO流
  • [Java] idea的调试介绍
  • P2670 [NOIP 2015 普及组] 扫雷游戏
  • 软件设计师考试三大核心算法考点深度解析(红黑树 / 拓扑排序 / KMP 算法)真题考点分析——求三连
  • centos7配置静态ip 网关 DNS
  • C++中的宏
  • 解码数据语言:如何优雅的进行数仓字典建设?
  • Web开发-Python应用Flask框架Jinja模版绑定路由参数传递页面解析SSTI注入
  • 协程+Flow:现代异步编程范式,替代RxJava的完整实践指南
  • PH热榜 | 2025-05-20
  • springboot框架 集成海康ISUP-SDK 并实现 协议透传给设备下发指令!
  • 武汉科技大学人工智能与演化计算实验室许志伟课题组参加第八届智能优化与调度学术会议
  • 【QT】QTableWidget获取width为100,与真实值不符问题解决
  • BUUCTF——Kookie
  • C语言学习之内存函数
  • Python打卡训练营day27-函数-装饰器
  • 深入解析MATLAB codegen生成MEX文件的原理与优势
  • MySQL高频面试八连问(附场景化解析)
  • 六个最伤脊柱的姿势,你可能天天在做
  • 6月底将返回中国,旅日大熊猫获颁“感谢状”
  • 水果预包装带来的环境成本谁来分担?
  • 广西壮族自治区政府主席蓝天立任上被查
  • 贵州仁怀通报“正新鸡排鸡腿里全是蛆”:已对同类产品封存送检
  • 北方产粮大省遭遇气象干旱,夏粮用水如何解决?