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

PHP CSRF 跨站請求偽造攻擊原理與防禦實作:Token 驗證完整範例

     編輯:PHP 綜合知識

什麼是 CSRF?

CSRF(Cross-Site Request Forgery)攻擊者誘導受害者在已登入的目標網站執行非預期操作(刪除資料、修改密碼、發文、轉帳)。因瀏覽器會自動攜帶目標域的 Cookie,伺服器無法分辨請求是否為使用者自願發起。

典型攻擊向量

  1. 隱藏圖片:<img src="https://bank.com/transfer?to=attacker&amount=1000">,受害者瀏覽含此圖的頁面即觸發 GET 請求。
  2. 自動提交表單:頁面載入即 form.submit() 發送 POST 請求。
  3. 偽裝連結:誘導點擊 <a href="https://forum.com/delete?id=123">看貓咪圖片</a>。

核心防禦策略:同步器 Token 模式

每個表單/狀態改變請求攜帶不可預測、使用者專屬、一次性的 Token,伺服端驗證 Token 有效性。

PHP Token 類別實作

<?php
class CsrfToken
{
    const SALT = 'your-application-specific-random-salt-change-in-production';
    const TTL  = 7200; // 2 小時

    /**
     * 產生 Token
     * @param string|int $userId 使用者唯一識別
     * @param string     $action 動作標識(可選,區分不同表單)
     * @return string 10 字元 Token
     */
    public static function generate($userId, $action = '')
    {
        $timeSlot = ceil(time() / self::TTL);
        $data     = $timeSlot . '|' . $action . '|' . $userId;
        return substr(hash_hmac('sha256', $data, self::SALT), 0, 10);
    }

    /**
     * 驗證 Token(允許前一個時段,避免邊界失效)
     */
    public static function validate($userId, $token, $action = '')
    {
        $currentSlot = ceil(time() / self::TTL);
        // 當前時段
        if (self::generate($userId, $action) === $token) {
            return true;
        }
        // 前一個時段(緩衝)
        $prevData = ($currentSlot - 1) . '|' . $action . '|' . $userId;
        if (substr(hash_hmac('sha256', $prevData, self::SALT), 0, 10) === $token) {
            return true;
        }
        return false;
    }
}
?>

表單整合範例

<!-- 表單頁面 -->
<form method="post" action="/delete_post.php">
    <input type="hidden" name="csrf_token" value="<?php echo CsrfToken::generate($currentUserId, 'delete_post'); ?>">
    <input type="hidden" name="post_id" value="123">
    <button type="submit">刪除文章</button>
</form>
<?php
// delete_post.php 處理端
session_start();
$userId = $_SESSION['user_id'] ?? 0;
$token  = $_POST['csrf_token'] ?? '';

if (!CsrfToken::validate($userId, $token, 'delete_post')) {
    http_response_code(403);
    die('CSRF Token 驗證失敗,請重新整理頁面再試。');
}

// Token 通過,執行刪除邏輯
$postId = (int)($_POST['post_id'] ?? 0);
// ... 刪除資料庫記錄
echo '刪除成功';
?>

進階防禦層級

層級措施適用場景
基礎同步 Token + SameSite Cookie所有狀態改變操作
強化雙重提交 Cookie(Token 同時存在 Cookie 與表單,JS 讀取 Cookie 寫入 Header)API、SPA、需防禦 Subdomain 攻擊
最高自定義 HTTP Header(X-Requested-With: XMLHttpRequest)+ Token,伺服端檢查 Header 存在純 AJAX 介面,瀏覽器同源策略天然阻擋跨域自定 Header

現代框架內建支援

  • Laravel:@csrf Blade 指令、VerifyCsrfToken 中介層自動驗證。
  • Symfony:csrf_token() Twig 函式、CsrfTokenManager 服務。
  • Yii2:ActiveForm 自動渲染隱藏 _csrf、Request::validateCsrfToken()。
  • ThinkPHP:{:token()} 模板標籤、Request::token() 驗證。

常見誤區

  • ❌ 只檢查 $_SERVER['HTTP_REFERER']:Referer 可偽造、隱私模式下不送出。
  • ❌ Token 寫死在 JS 檔案:等同無防禦。
  • ❌ 所有表單共用同一 Token:洩露一個即全失效,應按動作/頁面區分。
  • ❌ GET 請求執行刪除/修改:嚴禁,GET 應為冪等安全操作。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved