ThinkPHP框架本身不直接引入SSRF漏洞,但开发者若用用户可控参数构造HTTP请求且未严格校验URL,易触发SSRF;常见场景包括图片加载、远程资源抓取等,需重点排查用户输入直传、协议不限、内网IP未拦截等问题。

ThinkPHP(TP)框架本身不直接引入 SSRF 漏洞,但当开发者在业务逻辑中使用用户可控参数构造 HTTP 请求(如 file_get_contents、curl_exec、Requests::get 等),且未对传入的 URL 做严格校验时,就可能触发 SSRF。TP 的常见 SSRF 场景集中在图片加载、远程资源抓取、URL 重定向、第三方 API 调用等模块。
TP 中典型的 SSRF 触发点
以下几类代码模式在 TP 项目中高频出现,需重点排查:
-
用户输入直传请求函数:例如控制器中接收
$_GET['url']或$this->request->param('url')后,直接用于curl_init($url)或file_get_contents($url) -
URL 解析未限制协议与地址:未禁用
file://、gopher://、dict://等危险协议;未阻止解析出内网 IP(如127.0.0.1、192.168.x.x、10.x.x.x、172.16.x.x–172.31.x.x) -
域名解析绕过白名单:仅校验原始域名(如
example.com),但未做 DNS 解析后的真实 IP 校验,攻击者可通过 DNS 重绑定(DNS rebinding)绕过 -
TP 自带组件风险调用:部分老版本 TP 使用
think\facade\Cache或think\facade\Log时若配合自定义驱动或远程存储配置不当,也可能间接引发 SSRF(较罕见,但不可忽视)
TP 环境下的 SSRF 修复建议
修复应遵循“输入即不可信、请求即需约束”原则,不依赖前端或中间件过滤,所有校验必须落在服务端逻辑层。推荐分层防御:
-
强制白名单机制:只允许访问预设可信域名或 IP(如
oss.aliyuncs.com、api.weixin.qq.com)。使用正则或数组 in_array 判断,避免模糊匹配(如aliyuncs.com匹配到evil-aliyuncs.com) -
协议与格式双重校验:用
parse_url()解析用户输入,检查scheme是否仅为http或https;拒绝空 scheme、相对路径、含@的 URL(如http://attacker@127.0.0.1) -
真实 IP 黑名单拦截:对域名做
gethostbyname()或dns_get_record()解析,获取 A/AAAA 记录 IP,再判断是否属于 RFC1918 内网段或本地回环。注意处理 CNAME 链和 IPv6 场景 - 请求上下文隔离:关键下载/代理功能改由独立代理服务(如 Nginx 反向代理 + allow/deny 规则)或云函数承担,主应用不再发起外网请求
TP 代码修复示例(v6.x 推荐写法)
以下为控制器中安全获取远程图片的参考实现:
// ✅ 安全做法:白名单 + 协议校验 + IP 解析 + 超时控制
use think\facade\Log;
use GuzzleHttp\Client;
public function fetchImage()
{
$url = $this->request->param('url', '');
// 1. 基础格式校验
if (!filter_var($url, FILTER_VALIDATE_URL)) {
return json(['code' => 400, 'msg' => '非法URL格式']);
}
$parsed = parse_url($url);
if (!in_array(strtolower($parsed['scheme']), ['http', 'https'])) {
return json(['code' => 400, 'msg' => '仅支持 http/https 协议']);
}
// 2. 白名单域名比对(精确匹配)
$whitelist = ['img.example.com', 'cdn.example.org'];
$host = strtolower($parsed['host'] ?? '');
if (!in_array($host, $whitelist)) {
return json(['code' => 403, 'msg' => '域名不在白名单']);
}
// 3. 解析并校验真实IP(防DNS重绑定)
$ip = gethostbyname($host);
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) {
return json(['code' => 403, 'msg' => '目标IP为内网或保留地址']);
}
// 4. 发起受控请求
try {
$client = new Client(['timeout' => 5]);
$res = $client->get($url);
return $res->getBody();
} catch (\Exception $e) {
Log::error('SSRF fetch failed: ' . $e->getMessage());
return json(['code' => 500, 'msg' => '请求失败']);
}
}
补充注意事项
除代码修复外,还需关注部署与运维层面:
- 禁用 PHP 危险函数(如
allow_url_fopen=Off,disable_functions=file_get_contents, curl_exec, fsockopen),但注意不影响 TP 正常运行 - Web 服务器(Nginx/Apache)配置中限制 outbound 连接,例如通过 iptables 或 eBPF 限制 PHP-FPM 进程仅能访问指定出口 IP 和端口
- 定期扫描项目中所有
curl_*、file_get_contents、stream_context_create、Requests::*等调用点,建立请求白名单台账 - TP 升级至最新稳定版(v6.3+),关注官方安全公告,避免已知组件级 SSRF 风险(如旧版
think-captcha在特定配置下可能触发)











