服务端请求伪造 (SSRF)
| , 2 minutes reading.
1. 定义
服务端请求伪造 (Server-Side Request Forgery, SSRF) 是一种漏洞,允许攻击者诱使服务器端应用程序向攻击者指定的任意域发起 HTTP 请求。
在典型的 SSRF 攻击中,攻击者可能使服务器连接到组织基础设施内的内部服务,或强制服务器连接到任意外部系统,从而泄露敏感数据。
2. 技术原理
现代应用程序经常从用户提供的 URL 获取资源(例如”从 URL 导入”、“获取预览”、“Webhook 回调”)。
如果服务器不验证目标地址,攻击者可以:
- 访问内部服务: 请求
http://localhost:6379(Redis)、http://192.168.1.1/admin(内部管理后台)或云元数据端点。 - 端口扫描: 将服务器作为代理扫描内部网络。
- 绕过访问控制: 内部服务通常信任来自”localhost”的请求并跳过身份验证。
云元数据利用: 云服务提供商(AWS、GCP、Azure)在知名 URL 上公开实例元数据:
- AWS:
http://169.254.169.254/latest/meta-data/ - GCP:
http://metadata.google.internal/
这些端点返回 IAM 凭证、API 密钥和配置数据。
3. 攻击流程
sequenceDiagram
participant Attacker as 攻击者
participant WebApp as Web 应用程序
participant Meta as 云元数据服务
participant Internal as 内部数据库
Attacker->>WebApp: POST /fetch-url<br/>url=http://169.254.169.254/latest/meta-data/iam/
Note over WebApp: 服务器未经验证<br/>直接获取该 URL
WebApp->>Meta: GET /latest/meta-data/iam/security-credentials/
Meta-->>WebApp: IAM 角色凭证 JSON
WebApp-->>Attacker: 响应中包含 AWS 凭证
Note over Attacker: 攻击者现已获得<br/>云基础设施访问权限4. 真实案例:Capital One (2019)
目标: Capital One 的 AWS 基础设施。 漏洞类别: SSRF 导致云元数据访问 (CVE-2019-4872)。
漏洞背景: Capital One 使用的 Web 应用防火墙 (WAF) 存在 SSRF 漏洞。该 WAF 配置了一个权限过大的 IAM 角色。
攻击过程:
- 攻击者发现了 WAF 中的 SSRF 漏洞。
- 他们向
http://169.254.169.254/latest/meta-data/iam/security-credentials/发送请求。 - 获取了分配给 WAF IAM 角色的临时 AWS 凭证。
- 使用这些凭证访问了包含客户数据的 S3 存储桶。
影响: 超过 1 亿条客户记录被泄露,包括姓名、地址、信用评分和社会安全号码。这导致了 8000 万美元的罚款,并成为云安全领域的标志性案例。
5. 深度防御策略
A. 输入验证与白名单
绝不允许用户控制的 URL 访问任意目标。
- 白名单机制: 仅允许向已知的可信域发起请求。
- 默认拒绝: 阻止私有 IP 范围(10.x.x.x、172.16-31.x.x、192.168.x.x、127.x.x.x、169.254.x.x)。
- 协议限制: 仅允许
https://— 阻止file://、gopher://、dict://。
B. DNS 解析验证
攻击者可以使用 DNS 重绑定或解析为内部 IP 的域名来绕过 IP 黑名单。
- 机制: 先解析主机名,然后在发起请求前验证 IP 地址。
- 二次检查: 在 DNS 解析后再次验证 IP(防止 TOCTOU 攻击)。
C. 网络隔离
隔离需要获取外部 URL 的服务器。
- 防火墙规则: 获取用户提供 URL 的服务器不应有权访问内部服务或元数据端点。
- 专用代理: 通过具有严格白名单的加固代理路由所有出站请求。
D. 禁用云元数据(或使用 IMDSv2)
- AWS IMDSv2: 需要通过 PUT 请求获取会话令牌,使 SSRF 利用变得更加困难。
- 阻止元数据: 如果不需要,使用防火墙规则阻止对 169.254.169.254 的访问。
# AWS:在 EC2 实例上强制使用 IMDSv2
aws ec2 modify-instance-metadata-options \
--instance-id i-1234567890abcdef0 \
--http-tokens required