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

PHP 防止 CSRF 攻擊:驗證正常訪問與外部訪問的 Token 機制

     編輯:PHP 相關知識

前言

跨站請求偽造 (CSRF) 是常見的 Web 安全漏洞。攻擊者誘導已登入用戶訪問惡意頁面,在用戶不知情下向目標站點發送偽造請求。防禦核心在於「驗證請求來源」,最經典做法是使用 同步器 Token 模式:伺服器產生唯一 Token 存入 Session,表單攜帶 Token 提交,伺服器比對驗證。本文示範 PHP 實作該機制的完整流程。

核心原理

  1. 用戶請求表單頁面時,伺服器產生隨機 Token,寫入 $_SESSION['token'] 並嵌入表單隱藏欄位。
  2. 用戶提交表單,瀏覽器自動攜帶 Token(隱藏欄位)。
  3. 伺服器接收請求,比對 $_POST['token'] 與 $_SESSION['token'] 是否一致。
  4. 一致 → 正常訪問;不一致或缺失 → 外部/偽造訪問,拒絕處理。

完整代碼範例

<?php
session_start();

// 1. 處理表單提交
if (isset($_POST['check']) && !empty($_POST['name'])) {
    // 驗證 Token
    if (hash_equals($_SESSION['check'] ?? '', $_POST['check'])) {
        echo "正常訪問:Token 驗證通過";
        // 實際業務邏輯:儲存資料、發送郵件等
    } else {
        echo "外部訪問:Token 驗證失敗,疑似 CSRF 攻擊";
        // 記錄日誌、封鎖 IP 等防禦措施
    }
}

// 2. 產生新 Token(每次請求更新,或僅在表單頁產生)
$token = bin2hex(random_bytes(32)); // 密碼學安全隨機字串
$_SESSION['check'] = $token;
?>

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>CSRF Token 示例</title></head>
<body>
<h2>提交表單</h2>
<form method="post" action="">
  <label>姓名:<input type="text" name="name" required></label><br><br>
  <input type="hidden" name="check" value="<?php echo $token; ?>">
  <button type="submit">送出</button>
</form>
</body>
</html>

關鍵安全細節

1. 使用 hash_equals() 防止時序攻擊

直接用 == 或 === 比較字串會因長度不同提早返回,導致時序側通道洩露資訊。hash_equals() 以恆定時間比較,避免此風險。

2. Token 應具備不可預測性

  • 使用 random_bytes() / openssl_random_pseudo_bytes() 產生高熵值隨機字串。
  • 避免使用 md5(uniqid(rand(), true)) 等舊式做法,熵值不足且可被預測。

3. Token 存儲與生命週期

  • 儲存於 Session(伺服器端),不暴露於 URL 或 Cookie。
  • 可採用「每請求一 Token」或「每表單一 Token」策略;前者安全性較高,但可能導致多標籤頁操作失效,需權衡 UX。
  • 敏感操作(修改密碼、轉帳)建議加入二次驗證(簡訊、Email、密碼確認)。

4. SameSite Cookie 屬性作為纵深防禦

在 session_set_cookie_params() 或 php.ini 設定 session.cookie_samesite = Strict (或 Lax),瀏覽器將不在跨站請求中攜帶 Session Cookie,進一步降低 CSRF 風險。

進階:統一中介層實作

在現代框架 (Laravel, Symfony, ThinkPHP) 中,CSRF 防護通常內建於中介層,自動為所有非 GET 請求驗證 Token。若使用原生 PHP,可建立 csrf_verify() 函數並在所有需保護的入口檔案 require:

<?php
function csrf_verify() {
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        session_start();
        if (!hash_equals($_SESSION['csrf_token'] ?? '', $_POST['csrf_token'] ?? '')) {
            http_response_code(403);
            exit('CSRF token validation failed');
        }
    }
}

// 在每個處理 POST 的腳本最開頭呼叫
csrf_verify();
?>

總結

Token 驗證是防禦 CSRF 最有效、成本最低的手段。關鍵在於:安全隨機產生、Session 端儲存、恆定時間比對、SameSite Cookie 輔助。將此機制封裝為可複用的函數或中介層,即可為應用程式建立堅實的第一道防線。

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