flawopen.com/ssrf/Php

● CWE-918 · 高危
安全研究 · FlawOpen

漏洞深度剖析:Server-Side Request Forgery in PHP

How curl_exec in PHP exposes internal networks, and how to filter IPs using FILTER_VALIDATE_IP and CURLOPT_FOLLOWLOCATION.

💡 通俗易懂的原理解析 (ELI5)

想象一下,你派办公室助理去公共快递站取包裹,却故意给他留了总经理办公室带锁保险箱的内部地址。因为助理佩戴着公司内部通行工牌,保安直接放行,他便打开保险箱将公司核心机密交给了你。

核心概念与专有名词

Web Application Security
技术概念 (Web Application Security):Core architecture component affected by CWE-918.
CWE-918
技术概念 (CWE-918):Standard Common Weakness Enumeration classification for ssrf-php.
Defense-in-Depth
技术概念 (Defense-in-Depth):Multi-layered engineering verification and runtime boundary isolation.

攻击执行流程分解

Step 1

接收不可信远程 URL

应用程序接受用户提交的外部 URL 用于拉取头像、Webhook 推送或生成网页预览。

Step 2

指向内部专用网络与元数据服务

攻击者输入指向内网回环地址或云厂商元数据接口(如 http://169.254.169.254/latest/meta-data/)的地址。

Step 3

未受限制的内部网络套接字请求

服务器内部 HTTP 客户端直接从受信任的私有 VPC 发起网络请求,未做 IP 白名单与私有地址段校验。

Step 4

云身份凭证与敏感数据外泄

内部元数据服务信任来自同主机的请求,回传临时 IAM 访问凭据、Kubernetes Token 或管理后台内容。

源代码对比:漏洞与安全实现

✕ 存在漏洞的实现
<?php
// VULNERABLE: file_get_contents on user-controlled URL
$url = $_GET['url'];

// Attacker input: http://169.254.169.254/latest/meta-data/
$content = file_get_contents($url);

echo $content;
?>
✓ 加固后的安全修复
<?php
// HARDENED: Parse URL, resolve DNS, filter private IPs, and disable redirects
$url = $_GET['url'] ?? '';

$parsed = parse_url($url);
if (!$parsed || !in_array(strtolower($parsed['scheme'] ?? ''), ['http', 'https'], true)) {
    http_response_code(400);
    exit('Invalid URL scheme');
}

$host = $parsed['host'] ?? '';
$ips = gethostbynamel($host);

if (!$ips) {
    http_response_code(400);
    exit('Unable to resolve host');
}

// Check every resolved IP address
foreach ($ips as $ip) {
    if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
        http_response_code(403);
        exit('Access to private/internal address denied');
    }
}

// Fetch using cURL with redirects disabled
$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => false, // Prevent redirect bypasses
    CURLOPT_TIMEOUT        => 3,
    CURLOPT_PROTOCOLS      => CURLPROTO_HTTP | CURLPROTO_HTTPS,
]);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
?>

工程与系统安全加固清单

References