隨著 Web 應(yīng)用程序的發(fā)展和普及,網(wǎng)絡(luò)安全問題變得越來越重要。跨站請求偽造(CSRF)攻擊成為了其中一種常見的攻擊手段。CSRF攻擊是指攻擊者通過仿冒合法用戶的請求來執(zhí)行一些惡意操作,例如在用戶沒有意識到的情況下轉(zhuǎn)賬、修改密碼等。為了保護(hù)用戶和 Web 應(yīng)用程序的安全,開發(fā)者需要采取措施來防御此類攻擊。本文將介紹如何使用 PHP 來防御CSRF攻擊。
什么是CSRF?
CSRF,全稱為Cross-Site Request Forgery(跨站請求偽造),是一種常見的網(wǎng)絡(luò)安全漏洞和攻擊方式。它利用了Web應(yīng)用程序中的信任機(jī)制,通過欺騙用戶在已登錄的狀態(tài)下執(zhí)行非意愿的操作,從而導(dǎo)致未經(jīng)授權(quán)的請求被發(fā)送到目標(biāo)網(wǎng)站。
CSRF攻擊的基本原理
- 用戶在已登錄的狀態(tài)下訪問惡意網(wǎng)站或點(diǎn)擊惡意鏈接。
- 惡意網(wǎng)站或鏈接中包含了對目標(biāo)網(wǎng)站的請求,該請求可能是修改用戶個(gè)人信息、進(jìn)行資金轉(zhuǎn)賬、刪除數(shù)據(jù)等未經(jīng)授權(quán)的操作。
- 用戶的瀏覽器會(huì)自動(dòng)發(fā)送該請求,因?yàn)橛脩粢呀?jīng)在目標(biāo)網(wǎng)站中登錄并保留了有效的身份驗(yàn)證憑證(如Cookie)。
- 目標(biāo)網(wǎng)站接收到請求后,無法分辨這是來自用戶的合法請求還是惡意請求,并按照請求執(zhí)行了相應(yīng)的操作。
生成和驗(yàn)證CSRF令牌
生成CSRF令牌
session_start();
$token = bin2hex(random_bytes(32)); // 生成32個(gè)字節(jié)的隨機(jī)令牌
$_SESSION['csrf_token'] = $token; // 將令牌存儲在會(huì)話中
在表單中嵌入CSRF令牌
<form action="process.php" method="POST">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
<!-- 其他表單字段 -->
<button type="submit">提交</button>
</form>
驗(yàn)證CSRF令牌
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
// 令牌驗(yàn)證失敗,執(zhí)行相應(yīng)的錯(cuò)誤處理
die("CSRF攻擊檢測到!請求被拒絕。");
}
// 令牌驗(yàn)證成功,繼續(xù)處理請求
}
同源檢測
檢查請求的來源頭部
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$referer = $_SERVER['HTTP_REFERER'];
$origin = $_SERVER['HTTP_ORIGIN'];
$allowedOrigins = array('https://example.com', 'https://www.example.com'); // 允許的合法來源
if (!in_array($referer, $allowedOrigins) || !in_array($origin, $allowedOrigins)) {
// 來源驗(yàn)證失敗,執(zhí)行相應(yīng)的錯(cuò)誤處理
die("CSRF攻擊檢測到!請求被拒絕。");
}
// 來源驗(yàn)證成功,繼續(xù)處理請求
}
添加驗(yàn)證碼
生成和驗(yàn)證驗(yàn)證碼
session_start();
$randomNumber = rand(1000, 9999); // 生成隨機(jī)驗(yàn)證碼
$_SESSION['captcha'] = $randomNumber; // 將驗(yàn)證碼存儲在會(huì)話中
// 在表單中顯示驗(yàn)證碼圖像
<img src="captcha.php" alt="驗(yàn)證碼">
// 驗(yàn)證用戶輸入的驗(yàn)證碼
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_POST['captcha']) || $_POST['captcha'] !== $_SESSION['captcha']) {
// 驗(yàn)證碼驗(yàn)證失敗,執(zhí)行相應(yīng)的錯(cuò)誤處理
die("驗(yàn)證碼驗(yàn)證失??!請求被拒絕。");
}
// 驗(yàn)證碼驗(yàn)證成功,繼續(xù)處理請求
}
設(shè)置HTTP頭部
設(shè)置SameSite屬性為Strict或Lax
header('Set-Cookie: mycookie=value; SameSite=Strict');
或
header('Set-Cookie: mycookie=value; SameSite=Lax');