PHP CSRF防护全攻略:从原理到实战

2025-12-16 1175阅读

一、什么是CSRF攻击?

跨站请求伪造(Cross-Site Request Forgery,简称CSRF或XSRF)是一种常见的Web安全漏洞,攻击者通过诱导用户在已认证的状态下执行非预期操作(如转账、删除数据、修改密码等)。其核心原理是利用用户浏览器自动携带的Cookie凭证,伪造合法用户的请求。

二、CSRF攻击的原理与危害

2.1 攻击流程

  1. 用户已登录:用户访问并登录目标网站(如银行、电商平台),浏览器自动保存Cookie。
  2. 攻击者构造恶意请求:攻击者在钓鱼页面或第三方网站中嵌入隐藏表单/链接,伪造指向目标网站的敏感操作接口(如/transfer.php)。
  3. 用户触发请求:用户在不知情的情况下点击恶意链接或提交表单,浏览器自动携带Cookie发送请求。
  4. 完成非预期操作:目标网站因验证通过(仅检查Cookie),误认为是用户主动操作,执行攻击者伪造的请求。

2.2 典型场景

  • 转账攻击:攻击者在钓鱼页面放一个隐藏表单,提交到银行转账接口,用户点击后完成转账。
  • 删除数据:伪造GET请求(如/delete.php?id=1),用户点击后直接删除数据。
  • 修改密码:诱导用户提交包含新密码的表单,攻击者通过伪造请求修改密码。

三、PHP应用中的常见CSRF漏洞

3.1 未验证Token的表单提交

// 漏洞示例:修改个人信息的表单(无Token验证)
<form action="/update_profile.php" method="post">
    <input type="text" name="email" value="user@example.com">
    <input type="submit" value="更新">
</form>

攻击者可伪造请求提交恶意邮箱,用户点击后直接覆盖原邮箱。

3.2 使用GET请求执行敏感操作

// 漏洞示例:删除用户数据的GET请求
<a href="/delete_user.php?id=123">删除账号</a>

攻击者构造链接(如钓鱼页面中的隐藏<a>标签),用户点击后直接执行删除。

四、PHP CSRF防护核心方案

4.1 CSRF Token验证(最推荐)

原理:在用户会话中生成唯一Token,存储在Session或Cookie中,同时在请求中携带Token参数。服务器验证Token一致性,不一致则拒绝请求。

实现步骤

  1. 生成Token:在用户访问页面时,生成随机Token并存储到Session。
  2. 前端渲染Token:将Token注入表单隐藏字段。
  3. 后端验证Token:提交请求时,检查Session中的Token与请求参数中的Token是否一致。

代码示例

// 1. 生成Token(Session存储)
session_start();
$csrf_token = bin2hex(random_bytes(32)); // 生成32字节随机字符串
$_SESSION['csrf_token'] = $csrf_token;

// 2. 前端表单(HTML)
<form action="/update_profile.php" method="post">
    <input type="hidden" name="csrf_token" value="<?php echo $csrf_token; ?>">
    <input type="text" name="email" value="user@example.com">
    <input type="submit" value="更新">
</form>

// 3. 后端验证(PHP)
session_start();
$submitted_token = $_POST['csrf_token'] ?? '';
$stored_token = $_SESSION['csrf_token'] ?? '';

if ($submitted_token !== $stored_token) {
    die("CSRF Token验证失败");
}
// 验证通过,执行敏感操作

适用场景:所有敏感操作(修改、删除、转账等)的POST请求。

4.2 SameSite Cookie属性(辅助防护)

原理:通过设置Cookie的SameSite属性,限制浏览器在跨域请求中自动携带Cookie,仅允许同域请求携带。

实现方式

  • PHP设置Cookie
    // 设置SameSite=Strict(仅同域请求携带Cookie)
    setcookie('PHPSESSID', session_id(), [
    'samesite' => 'Strict',
    'secure' => true, // HTTPS下使用
    'httponly' => true, // 防止JS读取
    'path' => '/'
    ]);
  • Nginx/Apache配置
    # Nginx配置(全局设置Cookie属性)
    add_header Set-Cookie "SameSite=Strict; Secure; HttpOnly; Path=/";

注意SameSite=Strict可能影响第三方登录(如OAuth),可使用Lax(允许GET请求跨域携带)。

4.3 验证Referer/Origin头

原理:检查HTTP请求头中的Referer(完整URL)或Origin(仅域名),确认请求来源是否合法。

代码示例

// 后端验证Referer
$allowed_referers = ['https://yourdomain.com', 'https://admin.yourdomain.com'];
$referer = $_SERVER['HTTP_REFERER'] ?? '';

// 检查是否包含合法域名(允许部分子域名)
if (!in_array(parse_url($referer, PHP_URL_HOST), $allowed_referers)) {
    die("非法请求来源");
}

局限性Referer可被伪造,且HTTPS跳转HTTP时可能丢失Referer

4.4 双重提交Cookie

原理:将CSRF Token同时存储在Cookie和请求参数中,服务器验证两者是否一致。

实现步骤

  1. 生成Token:存储在Cookie中(HttpOnly防止XSS读取)。
  2. 前端提交Token:在请求参数中携带Token。
  3. 后端验证:检查Cookie中的Token与请求参数中的Token是否一致。

代码示例

// 1. 生成Token并写入Cookie
setcookie('csrf_cookie', $csrf_token, [
    'samesite' => 'Lax',
    'httponly' => true,
    'path' => '/'
]);

// 2. 前端表单(参数携带Token)
<input type="hidden" name="csrf_cookie" value="<?php echo $csrf_token; ?>">

// 3. 后端验证
$cookie_token = $_COOKIE['csrf_cookie'] ?? '';
$param_token = $_POST['csrf_cookie'] ?? '';

if ($cookie_token !== $param_token) {
    die("CSRF验证失败");
}

4.5 业务逻辑增强(辅助手段)

原理:结合敏感操作的额外验证(如密码、验证码、短信验证),即使Token被绕过,也能阻止恶意操作。

示例

// 修改密码时需原密码验证
if ($_POST['old_password'] !== $user['password'] || 
    $_POST['new_password'] !== $_POST['confirm_password']) {
    die("密码验证失败");
}

五、PHP框架内置防护(如Laravel、Symfony)

5.1 Laravel框架

Laravel通过CSRF中间件自动验证Token,无需手动实现:

  • 生成Token:表单中使用@csrf指令自动渲染隐藏字段。
  • 后端验证VerifyCsrfToken中间件自动检查Session与请求参数中的Token。

5.2 Symfony框架

Symfony通过Csrf组件实现Token生成与验证:


use Symfony\Component\Security\Csrf\CsrfTokenManager;
$tokenManager = new CsrfTokenManager();
$token
文章版权声明:除非注明,否则均为Dark零点博客原创文章,转载或复制请以超链接形式并注明出处。

目录[+]