Web 漏洞实战全解析:CSRF 攻击原理、Token 防御机制与实验验证(上)

Web 漏洞实战全解析:CSRF 攻击原理、Token 防御机制与实验验证(上)

前言:为什么必须认真研究 CSRF?

在 Web 安全体系中,CSRF(Cross-Site Request Forgery,跨站请求伪造)往往被低估。

很多开发者认为:

"只要不出现 SQL 注入和 XSS,网站就是安全的。"

但在真实生产环境中,CSRF 造成的危害并不亚于任何其他漏洞。它不需要窃取用户密码,不需要控制服务器,甚至不需要用户察觉,就可以在用户已登录的状态下,悄悄完成:

  • 修改账号密码

  • 变更绑定邮箱

  • 提交订单

  • 删除数据

  • 转账支付

本实验将在一个可控、简化、可复现的环境中,完整演示:

  • CSRF 为什么会发生

  • Token 是如何工作的

  • 为什么"只用 Session 不够"

  • 如何通过代码彻底防御 CSRF

第一章 实验背景与理论基础

1.1 Web 身份认证的基本模型

现代 Web 应用通常采用 **"无状态 HTTP + 有状态 Session"**​ 的身份认证模型:

  1. 用户提交用户名和密码

  2. 服务端校验成功

  3. 服务端创建 Session

  4. 返回 SessionID 给客户端(Cookie)

  5. 浏览器自动携带 Cookie 请求资源

这一机制带来了极大的便利,但也埋下了 CSRF 的根源。

1.2 CSRF 的核心本质

CSRF 的本质是:

浏览器自动携带凭证 + 服务端仅依赖凭证判断身份

攻击者的核心逻辑不是"破解",而是"借用"。

CSRF 攻击成立的条件

条件 说明
用户已登录 浏览器保存了合法 Cookie
请求可被伪造 参数可预测
服务端未校验来源 仅依赖 Session
用户触发请求 点击链接 / 自动提交

只要四个条件同时满足,CSRF 攻击即可成功。


1.3 CSRF 与 XSS 的区别

对比项 CSRF XSS
是否窃取数据
是否控制浏览器 ✅(借) ✅(控)
是否需要脚本
攻击目标 用户身份 用户本身

第二章 实验环境设计与说明

2.1 实验目标

本实验旨在实现:

  1. 构建一个存在 CSRF 风险的业务场景

  2. 使用 Token 机制进行防御

  3. 验证 Token 的一次性有效性

  4. 使用 Burp Suite 复现攻击与拦截

2.2 实验拓扑结构

复制代码
┌────────────┐
│ 测试机     │
│ Firefox    │
│ Burp Suite │
└─────▲──────┘
      │ HTTP
┌─────┴──────┐
│ 靶机       │
│ PHPStudy   │
│ Apache+PHP │
└────────────┘

2.3 软件环境说明

组件 版本 作用
OS Windows 靶机系统
PHPStudy 最新版 集成环境
PHP ≥ 7.x 后端逻辑
Firefox ESR 测试浏览器
Burp Suite Community 攻击复现

2.4 目录结构设计

复制代码
C:/phpstudy/phptutorial/WWW/csrf/
│
├── login.html
├── login1.php
├── manage-defense.php
├── add-pass.php
└── password.txt

第三章 登录系统构建(实验基础)

3.1 登录页面的设计思想

登录是所有权限控制的前提。

在本实验中,登录系统承担两个职责:

  1. 验证用户身份

  2. 初始化 Session 状态


3.2 登录前端页面(login.html)

复制代码
<html>
<meta charset="utf-8">
<form action="login1.php" method="POST">
    username:<br>
    <input type="text" name="username"><br>
    password:<br>
    <input type="text" name="password"><br>
    <input type="submit" value="Submit">
</form>
</html>

📌 设计说明:

  • 使用 POST,避免密码出现在 URL

  • 无前端校验,降低干扰

  • 表单结构清晰,便于抓包分析


3.3 登录后端逻辑(login1.php)

复制代码
<?php
session_start();

$usr = $_POST['username'];
$pwd = $_POST['password'];

if ($usr === 'admin' && $pwd === 'admin') {
    $_SESSION["admin"] = 1;
    echo "登录成功";
} else {
    echo "登录失败";
}
?>

核心安全点

  • session_start()必须放在第一行

  • Session 是后续所有防御的基础

  • 登录态只写入 Session,不依赖 Cookie 自定义


3.4 登录验证结果

访问:

复制代码
http://<靶机IP>/csrf/login.html

输入:

复制代码
admin / admin

返回:

复制代码
登录成功

说明:

  • Session 已创建

  • 用户处于"已认证状态"

  • 浏览器自动维护会话

第四章 管理功能与 CSRF 风险点

4.1 管理页面存在的隐患

在没有任何 CSRF 防御的情况下,一个"修改密码"的功能天然具备风险:

  • 请求参数可预测

  • 无需二次确认

  • 浏览器自动携带 Cookie

攻击者只需诱导管理员访问:

复制代码
http://靶机/csrf/add-pass.php?password_new=123456&password_conf=123456

即可完成攻击。

4.2 为什么不能只靠 Session?

很多初学者误以为:

"我已经用了 Session,所以不会 CSRF。"

这是一个严重误区。

✅ Session 解决的是 你是谁

❌ Session 解决不了 请求是不是你主动发的

第五章 Token 防御机制设计(核心章节)

5.1 Token 的设计原则

原则 说明
不可预测 随机数 + 时间戳
服务端保存 存入 Session
单次有效 使用即销毁
表单绑定 隐藏字段提交

5.2 管理页面(manage-defense.php)

复制代码
<?php
session_start();
if ($_SESSION["admin"] != 1) {
    die("Not admin");
}

$csrf_token = sha1(mt_rand() . time() . "Impossible");
$_SESSION["csrf_token"] = $csrf_token;
?>

📌 说明:

  • mt_rand():提高随机性

  • time():防止重放

  • sha1():统一长度


5.3 表单中嵌入 Token

复制代码
<input type="hidden" name="csrf_token" value="<?php echo $csrf_token; ?>">

浏览器会自动提交该字段,用户无感知。

5.4 密码修改与 Token 校验(add-pass.php)

复制代码
<?php
session_start();
if ($_SESSION["admin"] != 1) {
    die("Not admin");
}

$token = $_GET['csrf_token'];
if (!isset($_SESSION["csrf_token"]) || $_SESSION["csrf_token"] !== $token) {
    die("CSRF attack detected!");
}

关键点:

  • 先判断是否存在

  • 再判断是否相等

  • 不等立即终止流程

5.5 Token 的一次性销毁

复制代码
unset($_SESSION["csrf_token"]);

这一步决定了:

  • 同一个 Token 只能用一次

  • 攻击者无法复用旧请求

第六章 CSRF 防御效果的实验验证

6.1 实验验证的总体思路

在完成了登录系统、管理页面以及 Token 校验机制的实现之后,必须回答一个核心问题:

这套 Token 防御方案,真的能挡住 CSRF 攻击吗?

为了科学、严谨地验证这一点,本实验设计了三类测试用例:

测试编号 测试目标 预期结果
T1 正常用户修改密码 成功
T2 重复提交同一 Token 失败
T3 删除或篡改 Token 失败

只有在 T1 成功,T2/T3 全部失败​ 的前提下,才能证明防御机制有效。

6.2 正常业务流程验证(基准测试)

6.2.1 操作流程

  1. 启动 PHPStudy

  2. 打开 Firefox

  3. 访问 http://靶机IP/csrf/login.html

  4. 使用 admin/admin登录

  5. 访问 manage-defense.php

  6. 输入新密码并确认提交

6.2.2 实际结果

  • 页面返回:

    复制代码
    pwd changed ok
  • password.txt文件中成功写入新密码

  • Session 中 Token 被销毁

说明:正常业务未受影响

6.3 基于 Burp Suite 的攻击复现准备

6.3.1 Burp Suite 工作原理简述

Burp Suite 是一款用于 Web 安全测试的拦截型代理工具,其核心能力包括:

  • 拦截 HTTP 请求

  • 修改请求参数

  • 重放历史请求

  • 自动化测试

在 CSRF 测试中,它用于模拟攻击者控制请求的场景。

6.3.2 浏览器代理配置

在 Firefox 中设置:

复制代码
HTTP Proxy: 127.0.0.1
Port: 8080

并关闭 HTTPS 拦截(本实验仅涉及 HTTP)。

6.4 攻击场景一:Token 复用攻击

6.4.1 攻击思路

攻击者假设:

  • 已经捕获过一次合法请求

  • 认为 Token 可以重复使用

  • 尝试直接重放请求

6.4.2 攻击步骤

  1. 登录系统

  2. 打开 manage-defense.php

  3. 修改密码并提交

  4. 在 Burp Suite 中拦截请求

  5. 复制完整 URL(含 Token)

  6. 使用 Repeater 模块再次发送

示例请求:

复制代码
GET /csrf/add-pass.php?password_new=123456&password_conf=123456&csrf_token=abc123 HTTP/1.1
Host: 192.168.56.101

6.4.3 攻击结果

页面返回:

复制代码
Don't csrf attack!!

并且:

  • 密码未被修改

  • password.txt无变化

Token 复用攻击被成功拦截

6.5 攻击场景二:Token 缺失攻击

6.5.1 攻击方式

攻击者直接构造请求,不包含 Token 参数

复制代码
GET /csrf/add-pass.php?password_new=123456&password_conf=123456 HTTP/1.1

6.5.2 结果分析

服务端逻辑:

复制代码
if (!isset($_SESSION["csrf_token"])) {
    die("CSRF attack detected!");
}

由于 Token 已被销毁或未传入,请求被立即终止。

缺失 Token 的请求全部失败

6.6 攻击场景三:Token 篡改攻击

6.6.1 攻击方式

攻击者尝试猜测或伪造 Token:

复制代码
GET /csrf/add-pass.php?password_new=123456&password_conf=123456&csrf_token=fake_token HTTP/1.1

6.6.2 结果分析

服务端校验:

复制代码
if ($_SESSION["csrf_token"] !== $token) {
    die("CSRF attack detected!");
}

字符串比对失败,流程终止。

Token 不可预测性得到验证

6.7 多浏览器环境验证

为进一步增强实验说服力,在以下环境中重复测试:

浏览器 结果
Firefox
Chrome
Edge

说明 Token 校验与浏览器无关,只与 Session 状态有关

第七章 Token 防御机制的深度分析

7.1 为什么 Token 能防 CSRF?

7.1.1 攻击者做不到的事情

能力 是否存在
读取目标站点 Session
读取 Token 值
预测 Token
复用 Token

CSRF 的本质是"借身份",而 Token 让"借不到"。

7.2 Token 与 Session 的关系

Token 并不是替代 Session,而是增强 Session

层级 作用
Cookie 维持会话
Session 记录登录态
Token 验证请求合法性

三者缺一不可。

7.3 一次性 Token 的重要性

如果 Token 可以被多次使用,那么:

  • 攻击者可以保存请求

  • 随时重放

  • 防御形同虚设

因此:

复制代码
unset($_SESSION["csrf_token"]);

是整个防御体系的最后一道保险

7.4 Token 生成算法的合理性分析

复制代码
sha1(mt_rand() . time() . "Impossible")
组成部分 作用
mt_rand() 提高随机性
time() 防止回放
静态字符串 增加破解成本
sha1() 固定长度

虽然 SHA-1 已不再适合加密用途,但在 CSRF 场景中足够安全

第八章 实验中发现的问题与改进建议

8.1 当前实现的局限性

问题 说明
使用 GET 提交密码 不安全
Token 未绑定用户 可被横向复用
无 Token 过期时间 长期有效
无日志审计 难以溯源

8.2 改进方案(进阶)

8.2.1 使用 POST 提交

复制代码
<form method="POST">

8.2.2 Token 绑定用户 ID

复制代码
$_SESSION["csrf_token"][$uid] = $token;

8.2.3 设置 Token 有效期

复制代码
$_SESSION["csrf_time"] = time();

8.2.4 增加操作日志

复制代码
file_put_contents("log.txt", date("Y-m-d H:i:s") . " change pwd\n", FILE_APPEND);

第九章 实验结论(阶段性)

通过本阶段实验,可以得出以下结论:

  1. 仅靠 Session 无法防御 CSRF

  2. Token 能有效区分请求来源

  3. 一次性 Token 是关键

  4. Burp Suite 可完整复现攻击与防御过程

  • CSRF 与现代 Web 架构的关系

  • REST API 中的 CSRF 问题

  • SameSite Cookie 的作用与局限

  • 企业级 CSRF 防御体系设计

相关推荐
小救星小杜、13 小时前
new Router base的作用
前端·javascript·vue.js
程序二次开发13 小时前
wordpress 文章页,文章分类,单页,woocommerc 产品页,分类页添加.html后缀
大数据·前端·html·php
CodeSheep13 小时前
苦撑13年,创始人离职出走,拉勾终究还是倒下了…
前端·后端·程序员
a11177613 小时前
html制作的PPT(各种风格)提示词
前端·开源·html
cvcode_study13 小时前
Electron 制作自定义浏览器
前端·javascript·electron
JCJC错别字检测-田春峰13 小时前
字根秀秀 HTML 托管现已支持“用户登录”功能,一键变身 Web App!
前端·html·web app·网页托管
LuminousCPP13 小时前
C 语言通讯录补坑篇:终版遗留 Bug 修复,解决修改姓名输入错乱问题
c语言·开发语言·数据结构·经验分享·笔记·顺序表
中屹指纹浏览器13 小时前
2026年广告投放账号安全体系:指纹隔离、环境标准化与风控应对策略
经验分享·笔记