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