ThinkPHP中SSRF易发于调用file_get_contents()、curl_exec()等函数且直接使用用户输入URL的场景,如远程图片加载、Webhook回调、文档预览等;必须通过白名单校验、协议限制、DNS解析与私有IP过滤来防御,框架无内置SSRF防护中间件。

ThinkPHP里哪些地方容易出SSRF?
SSRF不是ThinkPHP框架自带的漏洞,而是你代码里调用了不安全的远程请求函数,并且把用户可控参数直接塞进去——比如 file_get_contents()、curl_exec()、fsockopen() 这类函数。常见场景有:图片远程加载、URL内容抓取、Webhook回调、文档预览接口、OSS签名生成时拼接后端地址等。
典型错误写法:
$url = input('url'); // 用户传啥就用啥
$content = file_get_contents($url); // 直接请求
攻击者传 http://127.0.0.1:8080/admin/api 或 file:///etc/passwd 就能读内网或本地文件。
怎么过滤用户传入的URL才安全?
不能只靠黑名单(比如禁止 127.0.0.1),因为绕过方式太多(0.0.0.0、[::1]、域名解析、短链接、302跳转等)。必须做白名单校验 + 协议限制 + DNS解析控制。
立即学习“PHP免费学习笔记(深入)”;
- 强制只允许
http和https协议,拒绝file、gopher、dict、ftp等危险协议 - 用
parse_url()提取host,再用gethostbyname()或dns_get_record()做真实IP解析,排除私有地址段(127.0.0.0/8、10.0.0.0/8、172.16.0.0/12、192.168.0.0/16、100.64.0.0/10) - 对域名做正则白名单,比如只允许匹配
^([a-z0-9-]+.)+[a-z]{2,}$,并拒绝含@、//、\的畸形URL - 设置cURL超时和最大重定向次数,防止DNS rebinding或长耗时探测
示例校验逻辑:
$url = input('url');
if (!filter_var($url, FILTER_VALIDATE_URL)) {
throw new Exception('Invalid URL format');
}
$parsed = parse_url($url);
if (!in_array($parsed['scheme'], ['http', 'https'])) {
throw new Exception('Only http/https allowed');
}
$ip = gethostbyname($parsed['host']);
if (ip2long($ip) === false || filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) {
throw new Exception('Invalid or private IP address');
}
ThinkPHP中间件能自动防SSRF吗?
不能。ThinkPHP没有内置SSRF防护中间件,middleware.csrf 只管CSRF,跟SSRF完全无关。所有涉及外部HTTP请求的业务逻辑,都得你自己加校验——哪怕只是调用了一个封装好的SDK方法,也要确认它内部有没有做过滤。
容易被忽略的点:
- 第三方SDK(如微信支付回调验证、阿里云OSS签名工具)如果接受用户传参构造请求,必须先校验再传入
- 日志或调试功能里用
file_get_contents($_GET['debug_url'])这种写法,是高危雷区 - 用
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true)时,重定向目标同样需要校验,不能只验原始URL - ThinkPHP的
Request::url()或input()返回值默认不做过滤,直接拼进cURL就是漏洞入口
有没有更稳妥的替代方案?
能不用用户可控URL就尽量不用。很多场景其实可以改成服务端预设列表 + ID映射:
- 图片加载 → 改为从数据库查配置项,用固定ID对应可信CDN路径
- Webhook回调 → 白名单管理后台维护合法域名/IP,运行时只从该表查地址
- 文档预览 → 用内部代理服务统一转发,前端只传文件ID,不传URL
实在绕不开,至少把请求逻辑抽成独立服务(如用Go/Python写个隔离的fetcher),通过消息队列通信,避免PHP进程直连不可信网络目标。
SSRF的关键不在“怎么修一个函数”,而在“谁有权决定请求发给谁”——这个决策点必须收口、可审计、带白名单,而不是散落在几十个控制器方法里靠人工判断。



















