SSRF 入门指南

● SSRF 入门指南

SSRF 全称 Server-Side Request Forgery,中文叫「服务端请求伪造」。这是 Web
安全里非常经典也非常高频的一类漏洞。

一、先用一个生活比喻理解它

想象你去一家餐厅点外卖代购服务:

  • 你(攻击者)告诉服务员(服务器):“帮我去楼下便利店买瓶可乐。”
  • 服务员是个"老实人",你说去哪他就去哪。
  • 于是你改口说:“帮我去餐厅后厨的保险柜里拿点东西。”
  • 服务员因为在餐厅内部,有权限进后厨,真的就去帮你拿了。

关键点在于:你自己进不去后厨(内网),但服务器能进。你就骗服务器替你去访问那些你本来碰不到的地方。

这就是 SSRF 的本质:利用服务器当"跳板/代理",去访问攻击者自己无法直接访问的资源。

二、为什么会产生 SSRF?

当一个 Web 应用提供了「让服务器主动去访问某个 URL」的功能时,就可能出问题。常见场景:

只要用户能控制服务器要访问的地址,而后端又没做好校验,SSRF 就来了。

三、一个最简单的漏洞代码

一个"图片代理"接口:传入 url,服务器去下载并返回内容

@app.route(‘/fetch’)
def fetch():
url = request.args.get(‘url’) # 用户完全可控
resp = requests.get(url) # 服务器直接去访问,没做任何检查
return resp.content

正常用法:
GET /fetch?url=https://example.com/cat.jpg
服务器去下载猫图,返回给你。没问题。

攻击用法:
GET /fetch?url=http://127.0.0.1:8080/admin
GET /fetch?url=http://192.168.1.1/
GET /fetch?url=http://169.254.169.254/latest/meta-data/

你把地址换成服务器内部才能访问的地址,服务器傻乎乎地帮你访问了,然后把结果返回给你。

四、攻击者能拿到什么?(危害)

1. 探测和访问内网

外网的你 ping 不到 192.168.x.x,但服务器在内网里。你可以让它逐个访问内网 IP
和端口,画出内网地图(哪些机器活着、开了哪些服务)。

2. 攻击内网服务

内网里的服务往往"不设防"(以为外面进不来)。比如未授权的 Redis、Elasticsearch、内部管理后台,通过 SSRF
就能直接打。

3. 读取云服务器的敏感元数据 ⭐(最经典、危害最大)

云主机(AWS、阿里云等)有一个特殊地址 169.254.169.254,叫元数据服务(Metadata Service)。访问它能拿到:

http://169.254.169.254/latest/meta-data/iam/security-credentials/
→ 返回临时访问密钥(AccessKey)!拿到后攻击者就能以这台服务器的身份操作整个云账号,危害极大。很多重大安全事故都源
于此。

4. 读取本地文件

如果代码用的库支持 file:// 协议:
file:///etc/passwd
直接读服务器本地文件。

5. 绕过防火墙、发起进一步攻击

借助服务器身份做端口扫描、攻击第三方等。

五、常被利用的"协议"和"地址"

SSRF 不只是 http://,危险的协议还有很多(取决于后端用什么库):

file:// 读本地文件 file:///etc/passwd
http/https 常规请求
gopher:// 超强!可构造任意TCP数据,能打Redis/MySQL等
dict:// 探测端口、打Redis
ftp:// …

其中 gopher:// 是攻击者最爱,因为它能让服务器发送任意字节流,相当于可以伪造出完整的 Redis 命令、HTTP POST
请求等,把"只能 GET 访问"升级成"能执行任意操作"。

六、绕过防御的常见花招(重点!)

很多开发者会想:“我把 127.0.0.1 和内网 IP 拉黑不就行了?” 但绕过方法非常多:

1. 换 IP 的写法(都指向 127.0.0.1):
http://127.0.0.1
http://0.0.0.0
http://localhost
http://0177.0.0.1 # 八进制
http://2130706433 # 十进制(把IP当整数)
http://0x7f.0.0.1 # 十六进制
http://[::1] # IPv6

2. 利用域名解析:

  • 注册一个域名,把它的 DNS 解析记录指向 127.0.0.1 或内网 IP。校验时看着是正常域名,实际访问的是内网。

3. 302 跳转绕过:

  • 让服务器访问 http://evil.com(校验通过),但这个地址返回一个 302 跳转 到
    http://127.0.0.1/admin。服务器跟着跳转就中招了。

4. DNS Rebinding(DNS重绑定) ⭐ 高级:

  • 校验时域名解析成一个正常外网 IP(通过检查),但等服务器真正发起请求那一刻,DNS 又解析成了内网
    IP。利用"检查"和"使用"之间的时间差绕过。

5. 短网址、URL 特殊字符:
http://expected.com@127.0.0.1/ # @前面是"用户名",实际访问@后面的
http://127.0.0.1#expected.com

七、如何防御(开发者视角)

防御 SSRF 的核心思路是 “默认拒绝,只允许白名单”:

1. 白名单优先(最有效)

  • 不要用黑名单(总有绕过)。只允许访问明确列出的域名/IP。

2. 校验要在解析后、请求时进行

  • 先把域名解析成 IP,检查这个 IP 是不是内网地址,再用这个 IP 去请求(防 DNS Rebinding)。
  • 屏蔽的 IP 段:
    127.0.0.0/8 本地回环
    10.0.0.0/8 内网
    172.16.0.0/12 内网
    192.168.0.0/16 内网
    169.254.0.0/16 链路本地(含云元数据 169.254.169.254)
    ::1 / fc00::/7 IPv6 对应段

3. 禁用危险协议

  • 只允许 http 和 https,禁掉 file://、gopher://、dict:// 等。

4. 禁止跟随重定向(或跟随后重新校验目标 IP)。

5. 网络层隔离

  • 给这类"外联"服务单独部署,限制它的出网权限,连不到内网和元数据服务。
  • 云上启用 IMDSv2(需要令牌才能访问元数据,能大幅缓解)。

6. 不要把响应原样返回给用户

  • 减少信息泄露(比如报错信息、响应内容)。

八、一句话总结

▎ SSRF = 骗服务器替你去访问你本来够不着的地方(尤其是内网和云元数据)。
▎ 只要有"用户控制 URL、服务器去访问"的功能,就要警惕。防御的关键是 白名单 + 解析后校验 IP + 禁危险协议 + 网络隔离。