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

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

     編輯:PHP 相關知識

CSRF(Cross-Site Request Forgery)利用受害者已登入身份,誘導其瀏覽器向目標站點發送偽造請求。本文解析攻擊原理、實戰案例與多層次防禦策略。

攻擊原理

  1. 使用者登入 bank.com,瀏覽器持有 Session Cookie
  2. 攻擊者誘導使用者訪問 evil.com
  3. evil.com 頁面包含:<img src="https://bank.com/transfer?to=attacker&amount=10000">
  4. 瀏覽器自動攜帶 bank.com Cookie 發送請求
  5. 銀行伺服器驗證 Cookie 有效,執行轉帳

常見攻擊向量

向量範例特點
圖片標籤<img src="...">GET、自動載入、無需互動
表單自動提交JS form.submit()POST、可攜帶複雜參數
iframe 隱藏<iframe src="..." style="display:none">可執行多步驟流程
Link 預載入<link rel="prefetch" href="...">瀏覽器預測性載入

實戰案例:留言板刪除攻擊

<!-- 惡意頁面 -->
<img src="https://target.com/admin/delete.php?id=1">
<img src="https://target.com/admin/delete.php?id=2">
<img src="https://target.com/admin/delete.php?id=3">

管理員瀏覽惡意頁面 → 留言被批量刪除。

核心防禦:同步器令牌模式

在表單/請求中嵌入不可預測的 Token,伺服器驗證 Token 有效性。

輕量級 Token 類實作

<?php
class CsrfToken
{
    private const TTL = 7200; // 2 小時
    private const LENGTH = 32;

    public static function generate(string $sessionKey = 'csrf_token'): string
    {
        if (empty($_SESSION[$sessionKey]) || time() - $_SESSION[$sessionKey . '_time'] > self::TTL) {
            $_SESSION[$sessionKey] = bin2hex(random_bytes(self::LENGTH));
            $_SESSION[$sessionKey . '_time'] = time();
        }
        return $_SESSION[$sessionKey];
    }

    public static function validate(string $input, string $sessionKey = 'csrf_token'): bool
    {
        if (empty($_SESSION[$sessionKey]) || empty($input)) {
            return false;
        }
        // 等時比較,防時序攻擊
        return hash_equals($_SESSION[$sessionKey], $input);
    }

    public static function inputField(string $name = 'csrf_token'): string
    {
        return '<input type="hidden" name="' . $name . '" value="' . htmlspecialchars(self::generate()) . '">';
    }
}

表單整合

<form method="post" action="/transfer">
    <?= CsrfToken::inputField() ?>
    <input name="amount" type="number" required>
    <button>轉帳</button>
</form>

控制器驗證

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!CsrfToken::validate($_POST['csrf_token'] ?? '')) {
        http_response_code(403);
        die('CSRF Token 無效或過期');
    }
    // 正常處理...
}

進階防禦層次

1. SameSite Cookie(現代瀏覽器預設開啟)

 0,
    'path' => '/',
    'domain' => '',
    'secure' => true,      // 僅 HTTPS
    'httponly' => true,
    'samesite' => 'Strict' // 或 'Lax'
]);
session_start();
  • Strict:完全阻擋跨站請求攜帶 Cookie(最安全,可能影響正常導航)
  • Lax:允許頂層導航 GET 請求攜帶 Cookie(推薦平衡點)
  • None:跨站攜帶,**必須搭配 Secure**

2. 雙重提交 Cookie

前端讀取 Cookie 值放入 Header/Body,伺服器比對。適用 SPA + API 架構。

3. 自定義請求標頭

AJAX 請求加上 X-Requested-With: XMLHttpRequest,伺服器檢查。注意:fetch 預設不送,需手動加入。

4. 關鍵操作二次驗證

  • 修改密碼 → 輸入舊密碼
  • 轉帳/付款 → 簡訊/Email OTP
  • 刪除資料 → 確認對話框 + 密碼

框架內建支援

框架機制
Laravel@csrf Blade 指令 + VerifyCsrfToken 中介層
Symfonycsrf_token() Twig 函式 + CsrfTokenManager
CodeIgniter 4csrf_field() + CSRFProtection Filter
Yii2ActiveForm 自動渲染 + Request::validateCsrfToken()
SlimSlim\Csrf\Guard 中介層

檢查清單

  • ☑ 所有狀態改變操作(POST/PUT/DELETE/PATCH)驗證 CSRF
  • ☑ GET 請求**不**修改狀態(REST 原則)
  • ☑ Token 使用 random_bytes() 產生、hash_equals() 比對
  • ☑ Token 設定過期時間(如 1-2 小時)
  • ☑ Session Cookie 設定 SameSite=Lax 或 Strict
  • ☑ API 端點採用 Bearer Token / 簽名驗證,而非 Session Cookie
  • ☑ 定期滾動 Token(登入、權限變更後重新產生)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved