浅析 SSRF 漏洞及在 WordPress 中如何防护!

前几天刚写了「你简单用 AI 写的插件就安全吗?和大家盘点一下 WPJAM Basic 最近修复的三个安全漏洞」,今天就详细讲解一下其中的 SSRF 漏洞。

在网络安全领域,SSRF(Server-Side Request Forgery,服务端请求伪造) 是一种常见且危害极大的漏洞。许多开源内容管理系统(CMS)在处理外部资源时,稍有不慎就会落入 SSRF 的陷阱。

作为全球使用最广泛的 CMS,WordPress 是如何应对这一威胁的呢?答案就在于它内置的一系列 wp_safe_remote_* 安全函数及其底层的安检函数:wp_http_validate_url()

什么是 SSRF 漏洞?

简单来说,SSRF 是指攻击者利用服务端的身份去发起请求的漏洞。

在正常的业务场景中,很多功能需要服务器去下载或访问外部资源(例如:输入一个 RSS 订阅源、远程下载插件、或者抓取外链图片的缩略图)。

然而,如果程序没有对用户输入的 URL 进行严格的过滤,攻击者就可以恶意修改这个 URL,将其指向:

  1. 企业内网敏感服务:如:http://192.168.1.1/admin(探测或攻击内网路由器、交换机、管理后台)
  2. 本地回环地址:如:http://127.0.0.1:8080(访问服务器本地未授权的数据库或 Redis、Memcached 等组件)
  3. 云服务器元数据地址:例如 AWS/阿里云的元数据服务:http://169.254.169.254/(可能直接泄露敏感的 IAM 凭证和安全令牌)

由于这些请求是从“防火墙内部、被信任的服务器”发出的,传统的外部防火墙通常不会拦截,导致服务器沦为攻击者探测内网、窃取数据的“肉鸡”和跳板。

WordPress 中的隐患与传统函数

在 WordPress 开发中,向远程服务器发起 HTTP 请求是非常常见的操作(例如获取外链 RSS、下载插件、拉取头像等)。传统上,开发者可能会使用标准的 wp_remote_get()wp_remote_post() 函数。

这两个函数功能强大,但它们并不会对请求的 IP 地址进行严格的合规性检查。这意味着,如果用户输入的 URL 指向的是服务器自身的内网 IP,这两个普通函数依然会照常发起请求。如果在插件或主题开发中直接套用它们处理用户可控的参数,就会给网站留下巨大的 SSRF 隐患。

使用 wp_safe_remote_* 系列函数

为了彻底堵住这个安全漏洞,WordPress 官方推出了一套更为安全的函数:

wp_safe_remote_request()
wp_safe_remote_get()
wp_safe_remote_post() 
wp_safe_remote_head()

核心逻辑:在请求发出前,多做一步“安检”。

相比于普通函数,wp_safe_remote_* 在发起网络请求时,会自动执行以下严格的过滤机制:

  • 封杀内网 IP:自动拒绝所有指向私有 IP 协议族(如 10.0.0.0/8172.16.0.0/12192.168.0.0/16)的请求。
  • 封杀本地回环:拒绝 127.0.0.1localhost
  • 限制特殊端口:默认只允许标准的 HTTP(80)和 HTTPS(443)端口,防止攻击者利用服务器去扫描内网的其他奇葩端口(如 22、3306 等)。
  • 严防重定向绕过:即使初始 URL 看起来是合法的外部网站,如果该网站返回了一个重定向(302 Redirect)到内网的地址,安全函数也能在跟进重定向时及时将其拦截。

核心幕后功臣:wp_http_validate_url()

wp_safe_remote_* 系列函数之所以如此安全,全凭它在底层调用了一个核心验证函数:wp_http_validate_url()

这个函数像是一个严格的安检员,专门负责给传入的 URL 做体检。如果发现任何高危特征,立刻返回 false 拒绝请求。

让我们顺着 WordPress 的核心源码逻辑,来看看这位“安检员”是如何工作的:

1. 协议白名单校验 (仅限 HTTP / HTTPS)

$url = wp_kses_bad_protocol( $url, array( 'http', 'https' ) );
if ( ! $url || strtolower( $url ) !== strtolower( $original_url ) ) {
    return false;
}

原理:利用 wp_kses_bad_protocol() 强制限制协议。

目的只允许 httphttps 请求。直接封杀利用 file://(读取本地文件)、gopher://(构造复杂 TCP 流量)、ftp:// 等其他危险协议进行的 SSRF 扩展攻击。

2. 拒绝凭证与非法字符

if ( isset( $parsed_url['user'] ) || isset( $parsed_url['pass'] ) ) {
    return false;
}
if ( false !== strpbrk( $parsed_url['host'], ':#?[]' ) ) {
    return false;
}

目的:禁止 URL 中带有用户名和密码(如 [http://user:pass@example.com](http://user:pass@example.com)),防止身份凭证泄露。同时检测 Host 中是否包含 :#?[] 等特殊字符,防止攻击者利用解析器差异(Parser Differential)绕过检测(例如让 PHP 解析出的 Host 与底层 cURL 解析出的 Host 不一致)。

3. DNS 解析与 IP 黑名单检查 (防内网穿透)

如果请求的域名不是当前网站自身的 Host(即访问外部网络),函数会进入最严格的 IP 审查阶段:

if ( preg_match( '#^(([1-9]?\d|1\d\d|25[0-5]|2[0-4]\d)\.){3}([1-9]?\d|1\d\d|25[0-5]|2[0-4]\d)$#', $host ) ) {
    $ip = $host;
} else {
    $ip = gethostbyname( $host ); // 进行 DNS 解析获取真实 IP
    if ( $ip === $host ) { return false; } // 解析失败则拒绝
}

一旦拿到真实的 IPv4 地址,它会对其进行拆分检查

$parts = array_map( 'intval', explode( '.', $ip ) );
if ( 127 === $parts[0] || 10 === $parts[0] || 0 === $parts[0]
    || ( 172 === $parts[0] && 16 <= $parts[1] && 31 >= $parts[1] )
    || ( 192 === $parts[0] && 168 === $parts[1] )
) { ... }

拦截范围:无死角封杀 127.x.x.x(本地回环)、10.x.x.x172.16.x.x - 172.31.x.x192.168.x.x(标准私有内网)以及 0.x.x.x

扩展过滤钩子:如果在特殊的企业内网业务中确实需要请求内网资源,可以通过 http_request_host_is_external 过滤器手动放行。

4. 严格的端口白名单过滤

$allowed_ports = apply_filters( 'http_allowed_safe_ports', array( 80, 443, 8080 ), $host, $url );
if ( is_array( $allowed_ports ) && in_array( $port, $allowed_ports, true ) ) {
    return $url;
}

默认安全端口:WordPress 默认只放行 80 (HTTP)、443 (HTTPS) 和 8080 (常见 Web 备用端口)

扩展过滤钩子:如果业务需要支持其他端口(如 8443 端口的外部 API),可以使用 http_allowed_safe_ports 钩子追加放行端口,而无需关闭整个安全检查。

最佳实践:代码对比

作为开发者,在处理网络请求时应当养成良好的肌肉记忆:

危险写法(容易遭受 SSRF):

// 如果 $user_url 是 'http://127.0.0.1:8080/secret',服务器就会去访问自己的敏感服务
$response = wp_remote_get( $user_url );

安全写法(推荐):

// 如果 $user_url 指向内网,该函数会自动拦截并返回错误,确保内网安全
$response = wp_safe_remote_get( $user_url );

总结两句

安全无小事。在开发 WordPress 插件或主题时,只要请求的 URL 是由用户输入的、或者来自不可信的第三方,请务必停用普通的 wp_remote_* 函数,无条件切换到 wp_safe_remote_* 系列。

WPJAM Basic 最新版本中也已经全面将相关网络请求升级为了更为安全的 wp_safe_remote_* 函数,这一个小小的代码习惯,就能借助底层的 wp_http_validate_url 安检机制,帮你把绝大多数高危 SSRF 漏洞拒之门外,守护服务器与内网数据的安全。


©我爱水煮鱼,本站推荐使用的主机:阿里云,国外主机建议使用BlueHost

本站长期承接 WordPress 优化建站业务,请联系微信:「chenduopapa」。