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

PHP 預防 XSS 與 CSRF 攻擊:完整防護函式與最佳實踐

     編輯:PHP 相關知識

XSS (跨站腳本攻擊) 防護

核心原則

  1. 輸入過濾:不信任任何使用者輸入
  2. 輸出編碼:根據輸出語境 (HTML、JS、CSS、URL) 做對應編碼
  3. CSP 標頭:Content-Security-Policy 限制腳本來源
  4. HttpOnly Cookie:防止 JS 竊取 Session

通用 XSS 清洗函式 (參考 CodeIgniter/Laravel)

function xss_clean(string $data): string {
    // 1. 修正實體編碼
    $data = str_replace(['&','<','>'], ['&','<','>'], $data);
    $data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data);
    $data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data);
    $data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');

    // 2. 移除危險屬性 (on*, xmlns)
    $data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*>#iu', '$1>', $data);

    // 3. 移除 javascript:/vbscript: 協定
    $data = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`"\']*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $data);
    $data = preg_replace('#([a-z]*)[\x00-\x20]*=([`"\']*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2novbscript...', $data);

    // 4. 移除 expression/moz-binding (IE/舊 Firefox)
    $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`"\']*.*?expression[\x00-\x20]*\([^>]*>#i', '$1>', $data);
    $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`"\']*.*?behaviour[\x00-\x20]*\([^>]*>#i', '$1>', $data);

    // 5. 移除命名空間標籤
    $data = preg_replace('#]*>#i', '', $data);

    // 6. 遞迴移除 script/iframe 等標籤
    do {
        $old = $data;
        $data = preg_replace('#]*>#i', '', $data);
    } while ($old !== $data);

    return $data;
}

輸出編碼輔助函式

function h(string $str): string { // HTML 編碼
    return htmlspecialchars($str, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}
function js(string $str): string { // JavaScript 字串編碼
    return json_encode($str); // 含引號
}
function url(string $str): string { // URL 參數編碼
    return rawurlencode($str);
}
function attr(string $str): string { // HTML 屬性編碼
    return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}

模板中正確使用

<!-- HTML 內容 -->
<div><?= h($user_content) ?></div>

<!-- HTML 屬性 -->
<input value="<?= attr($input_val) ?>" />

<!-- JavaScript 變數 -->
<script> var msg = <?= js($message) ?>; </script>

<!-- URL 參數 -->
<a href="/search?q=<?= url($keyword) ?>">搜尋</a>

<!-- CSS 值 -->
<div style="color: <?= h($color) ?>">

CSRF (跨站請求偽造) 防護

雙重 Cookie / Token 模式

<?php
// 產生 Token (Session + Cookie)
function csrf_token(): string {
    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf_token'];
}

// 驗證
function csrf_verify(string $token): bool {
    return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
}

// 表單隱藏欄位
echo '';

// AJAX Header
// 前端: headers: {'X-CSRF-Token': token}
// 後端: $token = $_SERVER['HTTP_X_CSRF_TOKEN'] ?? $_POST['_token'];

SameSite Cookie (現代瀏覽器首選)

// php.ini 或 runtime
ini_set('session.cookie_samesite', 'Strict'); // 或 'Lax'
// Laravel/框架通常自動處理

完整安全標頭建議

header("X-Content-Type-Options: nosniff");
header("X-Frame-Options: DENY");
header("X-XSS-Protection: 1; mode=block");
header("Referrer-Policy: strict-origin-when-cross-origin");
header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https:; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'");

框架內建防護 (勿重複造輪子)

框架XSSCSRF
LaravelBlade {{ }} 自動編碼@csrf / VerifyCsrfToken 中介層
SymfonyTwig {{ }} 自動編碼CsrfTokenManager + Form 隱藏欄位
CodeIgniter 4esc() / Security 類csrf_field() / Filter
Yii 2Html::encode()Yii::$app->request->csrfToken
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved