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

PHP 解決 XMLHttpRequest 無法自定義 Referer:CURL 代理模式完整實作

     編輯:PHP 綜合知識

問題背景

瀏覽器安全策略禁止 JavaScript 在 XMLHttpRequest 或 fetch 中設定 Referer、User-Agent、Cookie 等敏感標頭。若需模擬特定來源存取第三方 API(如域名查詢、支付回調測試),必須在**伺服器端以 CURL 代理**轉發請求。

核心解決方案:PHP CURL 代理

<?php
// proxy.php — 通用 CURL 代理端點
$method = $_SERVER['REQUEST_METHOD'];
$targetUrl = $_GET['target_url'] ?? '';
if (!$targetUrl) die('Missing target_url');

$ch = curl_init($targetUrl);
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => $method,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_MAXREDIRS      => 5,
    CURLOPT_SSL_VERIFYPEER => false, // 僅測試環境;生產請驗證憑證
    CURLOPT_SSL_VERIFYHOST => false,
    CURLOPT_TIMEOUT        => 15,
    CURLOPT_CONNECTTIMEOUT => 5,
    // 透傳標頭(排除 Host、Connection 等跳躍標頭)
    CURLOPT_HTTPHEADER     => array_filter([
        'User-Agent: '      . ($_SERVER['HTTP_USER_AGENT'] ?? 'PHP Proxy'),
        'Referer: '         . ($_GET['referer'] ?? ''),
        'X-Requested-With: XMLHttpRequest',
        'Accept: '          . ($_SERVER['HTTP_ACCEPT'] ?? '*/*'),
        'Content-Type: '    . ($_SERVER['CONTENT_TYPE'] ?? 'application/x-www-form-urlencoded'),
    ]),
    // 處理請求主體
    CURLOPT_POSTFIELDS     => ($method === 'POST') ? file_get_contents('php://input') : null,
]);

$response = curl_exec($ch);
$errno    = curl_errno($ch);
$error    = curl_error($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($errno) {
    http_response_code(502);
    die(json_encode(['error' => 'CURL Error: ' . $error]));
}

// 透傳回應標頭(可選)
header('Content-Type: application/json; charset=utf-8');
http_response_code($httpCode);
echo $response;
?>

實戰範例:萬網域名查詢 API 代理

<?php
// check_domain.php — 前端 AJAX 呼叫此檔
$domain = $_GET['domain'] ?? ''; // 例:example
$tld    = $_GET['tld']    ?? '.com';

$url = 'https://pandavip.www.net.cn/check/check_ac1.cgi';
$post = 'domain=' . urlencode($domain . $tld);

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => $post,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_USERAGENT      => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    CURLOPT_COOKIE         => '__utma=...; __utmz=...', // 必要 Cookie
    CURLOPT_HTTPHEADER     => [
        'X-Requested-With: XMLHttpRequest',
        'Referer: https://pandavip.www.net.cn/cgi-bin/Check.cgi?queryType=0&domain1=' . $domain . '&domain=' . $domain . '&' . trim($tld, '.') . '=yes',
    ],
    CURLOPT_TIMEOUT        => 10,
]);
$result = curl_exec($ch);
curl_close($ch);

header('Content-Type: text/xml; charset=utf-8'); // 原 API 回傳 XML
echo $result;
?>

前端 AJAX 呼叫方式

// 原本無法自訂 Referer 的前端程式碼
fetch('/check_domain.php?domain=example&tld=.com')
  .then(r => r.text())
  .then(xml => console.log(new DOMParser().parseFromString(xml, 'text/xml')));

安全強化清單

風險對策
開放式代理被濫用僅允許白名單域名(parse_url($targetUrl, PHP_URL_HOST) 比對)、驗證 API Key、限制同 IP 頻率
敏感標頭洩漏勿透傳 Authorization、Cookie 等內部標頭至外部 API
SSRF (Server-Side Request Forgery)禁止存取內網 IP(10.x、172.16-31.x、192.168.x、127.0.0.1、169.254.x)、封鎖 file://、gopher:// 協定
回應體過大導致記憶體耗盡設定 CURLOPT_MAXFILESIZE、使用串流寫入暫存檔

進階:非同步代理佇列

若第三方 API 回應緩慢,可採用「發送請求 → 立即回傳 202 Accepted → 背景 Worker 執行 CURL → 結果存入 Redis → 前端輪詢/WebSocket 推送」架構,避免阻塞 PHP-FPM 進程。

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