首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP CSRF 跨站請求偽造攻擊原理與 Token 防禦實戰

     編輯:PHP 相關知識

前言

CSRF(Cross-Site Request Forgery)攻擊者誘導已登入用戶在不知情下向目標站點發送惡意請求。本文透過完整範例示範 Token 驗證機制的實作細節與最佳實踐。

一、攻擊原理示意

  1. 用戶登入 bank.com,瀏覽器儲存 Session Cookie。
  2. 攻擊者誘導用戶訪問惡意頁面 evil.com。
  3. evil.com 內嵌表單或圖片自動提交至 bank.com/transfer?to=attacker&amount=1000。
  4. 瀏覽器自動攜帶 Cookie 發送請求,伺服器以為是用戶合法操作。

二、Token 防禦核心邏輯

伺服器生成唯一、不可預測的 Token,存入 Session 並輸出至表單隱藏欄位。提交時比對 Session 與表單 Token 是否一致。

三、完整實作範例

1. 表單頁面(產生 Token)

<?php
session_start();

// 產生 Token:時間戳 + 隨機鹽值雜湊
$token_time = time();
$token = hash_hmac('sha256', $token_time . 'secret_salt', 'site_secret_key');

// 存入 Session
$_SESSION['csrf_token'] = $token;
$_SESSION['csrf_time']  = $token_time;
$expire_time = 600; // 10 分鐘有效
?>
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>CSRF Demo</title></head>
<body>
<form method="post" action="process.php">
    <input type="text" name="amount" placeholder="金額">
    <input type="hidden" name="csrf_token" value="<?php echo $token; ?>">
    <input type="hidden" name="csrf_time" value="<?php echo $token_time; ?>">
    <button type="submit">送出</button>
</form>
</body>
</html>

2. 處理頁面(驗證 Token)

<?php
session_start();

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $token      = $_POST['csrf_token'] ?? '';
    $token_time = (int)($_POST['csrf_time'] ?? 0);
    $expire     = 600;

    // 1. 檢查時效
    if (time() - $token_time > $expire) {
        die('Token 已過期,請重新整理頁面。');
    }

    // 2. 比對 Token(使用 hash_equals 防止時序攻擊)
    $expected = $_SESSION['csrf_token'] ?? '';
    if (!hash_equals($expected, $token)) {
        die('CSRF 驗證失敗,請求來源非法。');
    }

    // 3. 驗證通過,執行業務邏輯
    echo "轉帳成功!金額:{$_POST['amount']}";

    // 4. 銷毀 Token(一次性使用)
    unset($_SESSION['csrf_token'], $_SESSION['csrf_time']);
}
?>

四、進階防禦策略

策略說明適用場景
SameSite Cookie設定 Set-Cookie: ...; SameSite=Strict/Lax,瀏覽器自動阻擋跨站請求攜帶 Cookie現代瀏覽器,最簡單有效
雙重 Cookie 驗證Token 同時存 Cookie 與表單,JS 讀取 Cookie 送 HeaderAPI/SPA 架構
自定義請求標頭要求 X-Requested-With: XMLHttpRequest,簡單 AJAX 保護傳統 jQuery AJAX
驗證碼/再次確認密碼高風險操作(修改密碼、轉帳)二次驗證關鍵業務

五、常見錯誤與修正

Token 直接存在表單、未存 Session
攻擊者可讀取頁面取得 Token,必須雙向綁定 Session。
使用 md5(time()) 產生 Token
可預測,必須使用加密安全隨機源(random_bytes()、hash_hmac())。
未檢查 Token 時效
導致 Token 永久有效,增加洩露風險。
== 比對字串
易受時序攻擊,必須用 hash_equals()。

六、框架整合建議

  • Laravel:@csrf Blade 指令自動處理。
  • ThinkPHP:{:token()} 模板標籤 + 控制器 $this->checkToken()。
  • CodeIgniter:$this->security->get_csrf_hash() + 設定 $config['csrf_protection'] = TRUE;。
  • 原生專案:建立 CsrfGuard 中介層,統一攔截非 GET 請求驗證。

結語

CSRF 防禦的核心在於「請求來源驗證」。Token 機制雖經典,但需注意隨機性、時效性、一次性與安全比對。現代專案應優先啟用 SameSite Cookie,輔以 Token 雙重保險,構建纵深防禦體系。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved