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

PHP HTTP 響應拆分漏洞(CRLF 注入)分析與修復方案

     編輯:PHP 相關知識

漏洞原理

HTTP 響應拆分(HTTP Response Splitting),又稱 **CRLF 注入**。攻擊者通過控制輸入數據注入換行符(\r\n,URL 編碼為 %0d%0a),截斷原響應頭,注入偽造的響應頭與響應體,構造雙重響應,實現緩存投毒、XSS、釣魚等攻擊。

漏洞觸發點

所有將用戶輸入直接用於 HTTP 響應頭的函數:

  • header() —— 如 Location 重定向
  • setcookie() / setrawcookie() —— Cookie 值
  • session_id() —— Session ID 設置

經典漏洞代碼

<?php
// 直接使用用戶輸入構造重定向
header("Location: " . $_GET['page']);
?>

攻擊演示

請求:

GET /location.php?page=%0d%0aContent-Type:%20text/html%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aContent-Length:%20158%0d%0a%0d%0a<html><body><form%20method=post%20name=form1>%E5%B8%90%E5%8F%B7%20<input%20type=text%20name=username%20/%3E<br%20/%3E%E5%AF%86%E7%A0%81%20<input%20name=password%20type=password%20/%3E<br%20/%3E<input%20type=submit%20name=login%20value=%E7%99%BB%E5%BD%95%20/%3E</form></body></html> HTTP/1.1
Host: localhost

解碼後的注入內容:

Content-Type: text/html
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 158

<html><body><form method=post name=form1>帳號 <input type=text name=username /><br />密碼 <input name=password type=password /><br /><input type=submit name=login value=登錄 /></form></body></html>

服務器響應:

HTTP/1.1 302 Found
Location: https://www.00aq.com
...(原響應)

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 158

<html>...(攻擊者注入的偽造登錄頁)

✅ **一個請求產生兩個響應**,瀏覽器/代理可能解析第二個響應,導致用戶看到偽造頁面。

實戰排查案例

某站掃描器報告 /?r=XXXXX 存在 CRLF 漏洞。代碼審計發現:

<?php
$redirect = $_GET['r'];  // 直接賦值,無任何過濾
header("Location: $redirect");
?>

修復方案

方案一:輸入驗證與白名單(推薦)

<?php
$allowed_redirects = [
    'home' => '/index.php',
    'login' => '/login.php',
    'dashboard' => '/user/dashboard.php',
];

$key = $_GET['r'] ?? 'home';
$redirect_url = $allowed_redirects[$key] ?? '/index.php';

header("Location: $redirect_url");
exit;
?>

方案二:嚴格過濾 CRLF 字符

<?php
$redirect = $_GET['r'] ?? '/';

// 移除所有換行符及變體
$redirect = str_replace(["\r", "\n", "%0d", "%0a", "%0D", "%0A"], '', $redirect);

// 可選:僅允許相對路徑或特定域名
if (!preg_match('~^(/|https?://allowed\.domain\.com/)~', $redirect)) {
    $redirect = '/';
}

header("Location: $redirect");
exit;
?>

方案三:框架級統一防護(最佳實踐)

在框架入口/中間件統一過濾所有 header()、setcookie() 參數:

<?php
// 基礎控制器或中間件
class Response {
    public static function header(string $header, bool $replace = true, int $code = 0): void {
        // 過濾頭名稱與值中的 CRLF
        $header = preg_replace('/[\r\n]/', '', $header);
        header($header, $replace, $code);
    }
    
    public static function redirect(string $url, int $code = 302): void {
        $url = preg_replace('/[\r\n]/', '', $url);
        // 可選:驗證 URL 合法性
        self::header("Location: $url", true, $code);
        exit;
    }
    
    public static function setCookie(string $name, string $value = '', array $options = []): void {
        $value = preg_replace('/[\r\n]/', '', $value);
        setcookie($name, $value, $options);
    }
}
?>

纵深防禦:服務器配置加固

Nginx

# 隱藏版本信息
server_tokens off;

# 禁止非法頭字符(需 Nginx 1.19.1+)
# 更推薦在應用層處理

PHP 配置

; php.ini
expose_php = Off          ; 隱藏 PHP 版本
; disable_functions = header,setcookie,session_id  ; 極端情況可禁用,但會影響正常功能

Apache

ServerTokens Prod
ServerSignature Off

漏洞檢測方法

  1. 自動掃描:AWVS、Nessus、Burp Suite 掃描器均包含 CRLF 注入檢測插件
  2. 手工測試:在所有反射用戶輸入的重定向、Cookie 設置點提交 %0d%0aSet-Cookie:test=injected,觀察響應頭
  3. 代碼審計:搜尋 header(、setcookie(、session_id(,檢查參數來源是否經過過濾

總結

CRLF 注入雖屬經典漏洞,但近年在 API 重定向、OAuth 回調、多域名 Cookie 共享等場景頻發。核心修復原則:**絕不信任用戶輸入用於 HTTP 頭**,採用白名單驗證或框架級統一過濾,配合服務器配置加固,徹底消除風險。

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