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 防御体系设计

相关推荐
Avan_菜菜4 小时前
AI 能写代码了,为什么我反而开始要求它先写文档?
前端·github·ai编程
爱勇宝8 小时前
鸿蒙生态的下半场:开发者不只要能开发,还要能赚钱
android·前端·程序员
IT_陈寒11 小时前
SpringBoot这个自动配置坑我跳了三次
前端·人工智能·后端
kyriewen11 小时前
我用 AI 一周写完了整个项目,上线第一天就崩了——这是我踩过最贵的 5 个坑
前端·javascript·ai编程
牧艺12 小时前
从零到协同:构建类飞书在线文档系统的五个技术重难点
前端·人工智能
红尘散仙12 小时前
想写一个像样的终端 App?试试把 React 的开发体验搬进 Rust TUI
前端·rust
袋鼠云数栈UED团队13 小时前
一套 Spec-First 的 AI 编程工作流
前端·人工智能
袋鼠云数栈前端13 小时前
一套 Spec-First 的 AI 编程工作流
前端·ai+
angerdream13 小时前
Android手把手编写儿童手机远程监控App之vue3 路由守卫
前端
不服老的小黑哥13 小时前
AI规范驱动编程-harness工程项目实战
前端