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

PHP 頁面跳轉與偽造 HTTP Referer 技術詳解:fsockopen 與 cURL 實戰

     編輯:PHP 相關知識

前言

在開發采集、代理轉發、第三方登入回調等場景時,常需模擬瀏覽器行為發送 HTTP 請求,並控制 Referer、User-Agent 等 Header。PHP 原生 header('Location:...')、Meta Refresh、JS 跳轉均無法攜帶自訂 Referer。本文深入講解使用 fsockopen 底層 Socket 通訊與 cURL 高階庫實現偽造 Referer、POST/GET 請求、處理 301/302 重導向的完整技巧。

一、常見跳轉方式無法傳遞 Referer 的原因

  • header("Location: $url"):瀏覽器發起新請求,Referer 為原頁面或空。
  • <meta http-equiv="refresh" content="0;url=...">:同屬瀏覽器導向,Referer 由瀏覽器決定。
  • window.location.href = "...":客戶端導向,Referer 為當前頁。

結論: 必須在伺服端以 HTTP Client 身分發起請求,才能完全控制 Header。

二、fsockopen 實作偽造 Referer (原始 Socket)

適用於未安裝 cURL 擴充套件的環境,可精細控制每個 Header 與原始回應。

<?php
function socketRequest($url, $method = 'GET', $postData = '', $referer = '', $headers = []) {
    $parsed = parse_url($url);
    $host = $parsed['host'];
    $port = $parsed['port'] ?? ($parsed['scheme'] === 'https' ? 443 : 80);
    $path = $parsed['path'] ?? '/';
    if (!empty($parsed['query'])) $path .= '?' . $parsed['query'];

    // 建立連線 (支援 SSL)
    $fp = @fsockopen(($parsed['scheme'] === 'https' ? 'ssl://' : '') . $host, $port, $errno, $errstr, 10);
    if (!$fp) {
        throw new Exception("連線失敗: $errstr ($errno)");
    }

    // 組裝請求行
    $request = "$method $path HTTP/1.1\r\n";
    $request .= "Host: $host\r\n";
    $request .= "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36\r\n";
    $request .= "Referer: " . ($referer ?: $url) . "\r\n";
    $request .= "Connection: Close\r\n";

    // 自訂 Header
    foreach ($headers as $k => $v) {
        $request .= "$k: $v\r\n";
    }

    if ($method === 'POST') {
        $request .= "Content-Type: application/x-www-form-urlencoded\r\n";
        $request .= "Content-Length: " . strlen($postData) . "\r\n";
    }
    $request .= "\r\n";
    if ($method === 'POST') $request .= $postData;

    // 發送
    fwrite($fp, $request);

    // 接收回應
    $response = '';
    while (!feof($fp)) {
        $response .= fgets($fp, 4096);
    }
    fclose($fp);

    // 解析 Header 與 Body
    list($headerStr, $body) = explode("\r\n\r\n", $response, 2);
    $headerLines = explode("\r\n", $headerStr);
    $statusLine = array_shift($headerLines);
    $headers = [];
    foreach ($headerLines as $line) {
        list($k, $v) = explode(': ', $line, 2);
        $headers[$k] = $v;
    }

    return [
        'status'  => $statusLine,
        'headers' => $headers,
        'body'    => $body,
    ];
}

// 使用範例:偽造 Referer 為 google.com 訪問目標站
try {
    $result = socketRequest(
        'https://httpbin.org/get',
        'GET',
        '',
        'https://www.google.com/search?q=test'
    );
    echo "Status: {$result['status']}\n";
    echo "Referer seen by server: " . ($result['headers']['Referer'] ?? '無') . "\n";
    // 可進一步處理 301/302 Location 重導向
} catch (Exception $e) {
    echo "錯誤: " . $e->getMessage();
}
?>

三、cURL 實作 (推薦生產環境使用)

cURL 封裝度高、支援 HTTPS、Cookie 自動處理、多執行緒、超時控制、重導向追蹤,程式碼更簡潔健壯。

<?php
function curlRequest($url, $options = []) {
    $ch = curl_init();
    $defaults = [
        CURLOPT_URL            => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,   // 自動追蹤 301/302
        CURLOPT_MAXREDIRS      => 5,
        CURLOPT_SSL_VERIFYPEER => false,  // 測試用,生產請設 true 並配置 CA
        CURLOPT_SSL_VERIFYHOST => false,
        CURLOPT_USERAGENT      => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
        CURLOPT_TIMEOUT        => 10,
        CURLOPT_CONNECTTIMEOUT => 5,
        CURLOPT_HEADER         => true,   // 包含 Header 於回傳
    ];
    curl_setopt_array($ch, $defaults + $options);
    $response = curl_exec($ch);
    $errno = curl_errno($ch);
    $error = curl_error($ch);
    $info = curl_getinfo($ch);
    curl_close($ch);

    if ($errno) throw new Exception("cURL 錯誤 [$errno]: $error");

    // 分離 Header 與 Body
    $headerSize = $info['header_size'];
    $headerStr = substr($response, 0, $headerSize);
    $body = substr($response, $headerSize);

    return ['info' => $info, 'headers' => $headerStr, 'body' => $body];
}

// 範例 1:偽造 Referer 進行 GET
$res = curlRequest('https://httpbin.org/headers', [
    CURLOPT_REFERER => 'https://www.facebook.com/',
]);
echo $res['body']; // 可見 Referer 已被偽造

// 範例 2:偽造 Referer 進行 POST 表單提交
$res = curlRequest('https://httpbin.org/post', [
    CURLOPT_POST       => true,
    CURLOPT_POSTFIELDS => http_build_query(['username' => 'demo', 'password' => 'secret']),
    CURLOPT_REFERER    => 'https://example.com/login_page',
    CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'],
]);
echo $res['body'];

// 範例 3:不自動追蹤重導向,手動處理 302 (如需捕獲 Location)
$res = curlRequest('https://httpbin.org/redirect/1', [
    CURLOPT_FOLLOWLOCATION => false,
    CURLOPT_REFERER        => 'https://mysite.com/',
]);
// 從 Header 解析 Location
if (preg_match('/Location:\s*(\S+)/i', $res['headers'], $m)) {
    echo "重導向至: $m[1]";
}
?>

四、進階應用:跨站表單提交 (CSRF 模擬/測試)

結合 CURLOPT_COOKIEJAR/CURLOPT_COOKIEFILE 維持 Session,可模擬完整登入流程:

$cookieFile = sys_get_temp_dir() . '/cookie_' . md5($url) . '.txt';
$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_URL            => 'https://target.com/login',
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => http_build_query(['user'=>'a','pass'=>'b']),
    CURLOPT_COOKIEJAR      => $cookieFile,
    CURLOPT_COOKIEFILE     => $cookieFile,
    CURLOPT_REFERER        => 'https://target.com/login',
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_RETURNTRANSFER => true,
]);
curl_exec($ch);
// 後續請求自動攜帶 Cookie
curl_setopt($ch, CURLOPT_URL, 'https://target.com/user/profile');
curl_setopt($ch, CURLOPT_POST, false);
$profile = curl_exec($ch);
curl_close($ch);

五、安全與法律提醒

  • 偽造 Referer 屬於灰色地帶: 部分網站依賴 Referer 進行防盜鏈、統計分析或 CSRF 防禦。惡意繞過可能違反《電腦犯罪條例》或網站服務條款。
  • 合法用途: 自家系統整合測試、爬蟲遵守 robots.txt 且不超過頻率限制、API 代理轉發需保留原始 Referer。
  • 防禦建議: 重要操作請使用 CSRF Token、SameSite Cookie、驗證 Origin Header,不應單獨信任 Referer。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved