PHP CSRF防护:修订间差异
外观
Page creation by admin bot |
Page update by admin bot |
||
第1行: | 第1行: | ||
= PHP CSRF防护 = | = PHP CSRF防护 = | ||
'''跨站请求伪造'''(Cross-Site Request Forgery,简称CSRF)是一种常见的Web安全漏洞,攻击者通过诱导用户在已认证的Web应用中执行非预期的操作。PHP开发者必须理解并实施有效的CSRF防护措施,以确保应用的安全性。 | |||
== 什么是CSRF攻击? == | == 什么是CSRF攻击? == | ||
CSRF攻击利用了Web应用对用户浏览器的信任机制。当用户登录某个网站后,攻击者可以诱使用户访问恶意页面,该页面会向目标网站发送伪造的请求。由于用户的浏览器会自动携带认证信息(如Cookies),目标网站会误认为这是用户的合法操作。 | |||
=== 攻击流程示例 === | |||
<mermaid> | <mermaid> | ||
sequenceDiagram | sequenceDiagram | ||
participant 用户 | participant 用户 | ||
participant 恶意网站 | participant 恶意网站 | ||
participant | participant 目标网站 | ||
用户->> | |||
用户->>恶意网站: | 用户->>目标网站: 登录并获取会话Cookie | ||
恶意网站->> | 用户->>恶意网站: 访问攻击者构造的页面 | ||
恶意网站->>目标网站: 自动发送伪造请求(携带用户Cookie) | |||
目标网站-->>恶意网站: 执行非预期操作(如转账、改密) | |||
</mermaid> | </mermaid> | ||
== | == PHP中的CSRF防护机制 == | ||
=== 1. | === 1. 使用CSRF令牌 === | ||
最常用的防护方法是生成并验证CSRF令牌(Token)。基本原理是: | |||
* 服务器生成唯一令牌并存储在会话中 | |||
* 令牌随表单一起发送给客户端 | |||
* 表单提交时验证令牌是否匹配 | |||
==== 生成令牌 ==== | |||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
<?php | <?php | ||
session_start(); | session_start(); | ||
if (empty($_SESSION['csrf_token'])) { | |||
function generate_csrf_token() { | |||
if (empty($_SESSION['csrf_token'])) { | |||
$_SESSION['csrf_token'] = bin2hex(random_bytes(32)); | |||
} | |||
return $_SESSION['csrf_token']; | |||
} | } | ||
?> | ?> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== | ==== 在表单中包含令牌 ==== | ||
<syntaxhighlight lang="html"> | <syntaxhighlight lang="html"> | ||
<form action="process.php" method=" | <form action="process.php" method="post"> | ||
<input type="hidden" name="csrf_token" value="<?php echo | <input type="hidden" name="csrf_token" value="<?php echo generate_csrf_token(); ?>"> | ||
<!-- 其他表单字段 --> | <!-- 其他表单字段 --> | ||
<input type="submit" value="提交"> | <input type="submit" value="提交"> | ||
第43行: | 第50行: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== | ==== 验证令牌 ==== | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
<?php | <?php | ||
session_start(); | session_start(); | ||
if ($_SERVER['REQUEST_METHOD'] === 'POST') { | if ($_SERVER['REQUEST_METHOD'] === 'POST') { | ||
if (! | if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) { | ||
die("CSRF令牌验证失败!"); | die("CSRF令牌验证失败!"); | ||
} | } | ||
// 安全处理表单数据 | // 安全处理表单数据 | ||
// ... | |||
} | } | ||
?> | ?> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== | === 2. 同源策略与SameSite Cookie === | ||
PHP 7.3+支持设置SameSite Cookie属性,可有效防御CSRF: | |||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
<?php | |||
session_set_cookie_params([ | |||
'lifetime' => 86400, | |||
'path' => '/', | |||
'domain' => 'example.com', | |||
'secure' => true, | |||
'httponly' => true, | |||
'samesite' => 'Strict' | |||
]); | |||
session_start(); | |||
?> | |||
</syntaxhighlight> | </syntaxhighlight> | ||
* '''Strict''': 完全禁止跨站请求携带Cookie | |||
* '''Lax''': 允许安全方法(如GET)的跨站请求 | |||
== 实际案例 == | == 实际案例 == | ||
=== 银行转账场景 === | |||
假设有一个银行转账功能,没有CSRF防护的攻击流程: | |||
1. 用户登录银行网站(bank.com) | |||
2. 攻击者构造恶意页面: | |||
<syntaxhighlight lang="html"> | <syntaxhighlight lang="html"> | ||
<img src="https:// | <img src="https://bank.com/transfer?to=attacker&amount=1000" width="0" height="0"> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
3. 用户访问该页面时,自动发起转账请求 | |||
=== 防护后的解决方案 === | |||
实施CSRF令牌后: | |||
* 表单必须包含有效令牌 | |||
* 服务器验证令牌有效性 | |||
* 攻击者无法获取或预测令牌 | |||
== 高级防护技术 == | |||
=== 双重提交Cookie模式 === | |||
1. | 1. 服务器设置随机Cookie | ||
2. | 2. 表单提交时要求客户端发送相同值 | ||
3. | 3. 验证两者是否匹配 | ||
=== 自定义HTTP头 === | |||
对于AJAX请求,可以要求包含自定义头: | |||
<syntaxhighlight lang="javascript"> | |||
// jQuery示例 | |||
$.ajax({ | |||
url: 'api/action', | |||
headers: { 'X-CSRF-Token': '<?php echo generate_csrf_token(); ?>' } | |||
}); | |||
</syntaxhighlight> | |||
== 数学原理 == | == 数学原理 == | ||
CSRF防护的核心是确保请求包含攻击者无法预测的秘密值。从信息论角度看: | |||
<math> | <math> | ||
H | H(T) \geq 128 \text{ bits} | ||
</math> | </math> | ||
== | 其中<math>H(T)</math>是令牌T的熵,应至少128位才能抵抗暴力破解。 | ||
== 最佳实践 == | |||
* 为每个表单生成唯一令牌 | |||
* 令牌应有足够熵值(使用<code>random_bytes()</code>) | |||
* 重要操作应使用POST请求 | |||
* 结合SameSite Cookie属性 | |||
* 定期轮换令牌(但保持用户体验) | |||
== | == 常见错误 == | ||
* 在URL中传递令牌(可能被记录) | |||
* 全局重用同一个令牌 | |||
* 不验证请求方法(GET/POST) | |||
* 使用可预测的令牌生成算法 | |||
通过实施这些防护措施,PHP开发者可以显著降低CSRF攻击的风险,保护用户数据和系统安全。 | |||
[[Category:编程语言]] | [[Category:编程语言]] | ||
[[Category:PHP]] | [[Category:PHP]] | ||
[[Category: | [[Category:PHP安全编程]] |
2025年5月2日 (五) 00:29的最新版本
PHP CSRF防护[编辑 | 编辑源代码]
跨站请求伪造(Cross-Site Request Forgery,简称CSRF)是一种常见的Web安全漏洞,攻击者通过诱导用户在已认证的Web应用中执行非预期的操作。PHP开发者必须理解并实施有效的CSRF防护措施,以确保应用的安全性。
什么是CSRF攻击?[编辑 | 编辑源代码]
CSRF攻击利用了Web应用对用户浏览器的信任机制。当用户登录某个网站后,攻击者可以诱使用户访问恶意页面,该页面会向目标网站发送伪造的请求。由于用户的浏览器会自动携带认证信息(如Cookies),目标网站会误认为这是用户的合法操作。
攻击流程示例[编辑 | 编辑源代码]
PHP中的CSRF防护机制[编辑 | 编辑源代码]
1. 使用CSRF令牌[编辑 | 编辑源代码]
最常用的防护方法是生成并验证CSRF令牌(Token)。基本原理是:
- 服务器生成唯一令牌并存储在会话中
- 令牌随表单一起发送给客户端
- 表单提交时验证令牌是否匹配
生成令牌[编辑 | 编辑源代码]
<?php
session_start();
function generate_csrf_token() {
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}
?>
在表单中包含令牌[编辑 | 编辑源代码]
<form action="process.php" method="post">
<input type="hidden" name="csrf_token" value="<?php echo generate_csrf_token(); ?>">
<!-- 其他表单字段 -->
<input type="submit" value="提交">
</form>
验证令牌[编辑 | 编辑源代码]
<?php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
die("CSRF令牌验证失败!");
}
// 安全处理表单数据
// ...
}
?>
2. 同源策略与SameSite Cookie[编辑 | 编辑源代码]
PHP 7.3+支持设置SameSite Cookie属性,可有效防御CSRF:
<?php
session_set_cookie_params([
'lifetime' => 86400,
'path' => '/',
'domain' => 'example.com',
'secure' => true,
'httponly' => true,
'samesite' => 'Strict'
]);
session_start();
?>
- Strict: 完全禁止跨站请求携带Cookie
- Lax: 允许安全方法(如GET)的跨站请求
实际案例[编辑 | 编辑源代码]
银行转账场景[编辑 | 编辑源代码]
假设有一个银行转账功能,没有CSRF防护的攻击流程:
1. 用户登录银行网站(bank.com) 2. 攻击者构造恶意页面:
<img src="https://bank.com/transfer?to=attacker&amount=1000" width="0" height="0">
3. 用户访问该页面时,自动发起转账请求
防护后的解决方案[编辑 | 编辑源代码]
实施CSRF令牌后:
- 表单必须包含有效令牌
- 服务器验证令牌有效性
- 攻击者无法获取或预测令牌
高级防护技术[编辑 | 编辑源代码]
双重提交Cookie模式[编辑 | 编辑源代码]
1. 服务器设置随机Cookie 2. 表单提交时要求客户端发送相同值 3. 验证两者是否匹配
自定义HTTP头[编辑 | 编辑源代码]
对于AJAX请求,可以要求包含自定义头:
// jQuery示例
$.ajax({
url: 'api/action',
headers: { 'X-CSRF-Token': '<?php echo generate_csrf_token(); ?>' }
});
数学原理[编辑 | 编辑源代码]
CSRF防护的核心是确保请求包含攻击者无法预测的秘密值。从信息论角度看:
其中是令牌T的熵,应至少128位才能抵抗暴力破解。
最佳实践[编辑 | 编辑源代码]
- 为每个表单生成唯一令牌
- 令牌应有足够熵值(使用
random_bytes()
) - 重要操作应使用POST请求
- 结合SameSite Cookie属性
- 定期轮换令牌(但保持用户体验)
常见错误[编辑 | 编辑源代码]
- 在URL中传递令牌(可能被记录)
- 全局重用同一个令牌
- 不验证请求方法(GET/POST)
- 使用可预测的令牌生成算法
通过实施这些防护措施,PHP开发者可以显著降低CSRF攻击的风险,保护用户数据和系统安全。