服务器端请求伪造 SSRF 是攻击者诱导服务器去请求一个攻击者选择的目标,从而借“服务器身份”访问内网、云元数据、本机服务等外部网络访问不到的资源。由于服务器处在可信网络位置,SSRF 常被用来穿透隔离、读取元数据、探测内部拓扑。封堵靠目标白名单、协议限制、网络隔离与请求响应不直接回显。
前面我们讲的是“输入变代码”,这一节讲“输入变地址”。当服务端代码允许用户控制“接下来替我请求哪个 URL”时——抓图预览、地址解析、回调、外部资料同步都常这么干——它就把服务器的网络身份出借给了攻击者。攻击者填的地址不限于公开公网,还包括 127.0.0.1、内网 IP、云元数据服务地址。
很多应用提供“输入图片 URL,服务器抓图给你预览”的功能。实现示例(示意):
url = request.args.get('url') resp = requests.get(url) # 用服务器身份去请求 return serve_image(resp.content)
若不加限制,攻击者把 url 填成本机回环的某个管理端口,或填云厂商的元数据端点地址 169.254.169.254,服务器会带着自己的高权限身份去访问。这类地址只在内网可达,攻击者自己连不上,但借助服务器的出口就能探到、读到内容。
SSRF 成立有三个条件:一、用户能控制服务端发请求的目标地址;二、请求带着服务器的可信网络身份;三、服务器的网络位置比攻击者更“内”。三者叠加,攻击者就完成了一次“自己做不到、服务器做得到”的访问。它最典型的战利品是云元数据服务——如果拿到那份令牌,等于摸到了云账号的钥匙。要强调的一点是,SSRF 危害不只看“能不能读到”,更看“服务器坐在离什么近的地方”:靠近云账号、靠近数据库、靠近内部管理网,同样一个漏洞的杀伤完全不同。
治本不是“禁某些敏感 IP 列表”就行,因为可用的解析、重定向、IPv6、十六进制 IP 等多种写法能绕过黑名单。可靠做法是“默认拒绝、白名单放行”。
💡 关键直觉:凡代码里有“让用户给个地址,我们替你请求”的地方,就按 SSRF 排查。白名单是更稳的筑基——想想清楚“这个功能到底该允许连哪几个真正信任的目标”,把判断从“禁什么”改成“放什么”。
SSRF 和 CSRF 名字相近,初学容易混淆,实际上方向正好相反。CSRF 是“服务器把用户浏览器的请求当成用户意愿”,攻击者借的是浏览器的身份;SSRF 是“服务器替用户发起对别处的请求”,攻击者借的是服务器的网络身份。一个谁能发(浏览器)被当真,一个发向哪里(服务器)被控制。排查时先判断:这个请求是“浏览器替用户发”还是“服务器替我发”,方向定了,主攻路线也就定了。两者都可能靠白名单救场,但一个校验的是“请求是否有令牌”,一个校验的是“目标地址是否在可信列表里”,别用错武器。
背景:一个目标地址白名单为空、任意 URL 都能请求的演示抓图服务。操作:把地址填成 file 协议本地文件观察协议限制,再填内网相对地址观察响应。结果:可读取本地文件、响应被回显。解读:目标地址可控 + 协议未限 + 响应回显,三个条件都满足。变式:先改协议白名单只放 http/https,再上目标域名白名单,再开网络隔离切断内网,追加不回显配置——四步叠加后同样的载荷全部被挡,SSRF 闭环。
有一类服务很隐蔽地放大 SSRF:公司内部的代理、跳板机、文档预览、邮件链接转码、URL 安全检测等,本质都是“给个地址,我替你去访”。它们看起来人畜无害,一旦允许非受限的地址,就成了统一的 SSRF 跳板,攻击者只消找到一个入口就能对内部网络做横向发起。治理时记得给它单独上白名单:这类功能通常并不需要“访问任意 URL”,只需要访问有限的信任站点或特定协议,把目标列窄、把协议限定、把出网隔离,再从源头掐掉“任意地址都能请求”的默认态。补一句提醒:这类服务也是高价值的监控对象,一旦排查到有人频繁投递内网地址或元数据地址,往往是已有一处 SSRF 被激活的信号,别当作普通流量无视。
排查和写防御时,给一个能贴进评审的自问顺序:这个功能为什么需要服务端代发请求,如果真需要,它是不是只需要访问固定的少数目标;这些目标能不能用白名单写死,还是真的开放任意地址;就算开了白名单,返回内容要不要回显、回显到多细。三个问题分别击中 SSRF 的三个条件——目标可控、可信身份、有内容回显。答完基本能定下防护要用哪几招:把目标列窄、把协议限定、切断不必要出网、最小化回显。这套自问比背规则更顺,因为它逼你把“这个地址大概只能发给这几家”想清楚,白名单自然就有了脸谱。