import ipaddress, socket
ip = ipaddress.ip_address(socket.gethostbyname(host))
assert not (ip.is_private or ip.is_loopback or ip.is_link_local)

封面图功能传 url=http://127.0.0.1:8500/v1/agent/self,接口回 200,响应体是内网服务的注册信息。换成 169.254.169.254 也能拿到实例凭据。先别急着动参数,把报错原文和时间点记下来,顺序反了容易白折腾。

原因不复杂,服务端拿着用户给的地址直接发请求,没限制协议和解析后的 IP。域名解析发生在校验之后,前面那层判断等于没用。内网地址、回环地址、云厂商元数据地址全在可达范围内。

「SSRF 内网地址」确认了原因之后,改动尽量只碰那一处,顺手改的东西后面最容易出问题。改动写完就同步给同事,下一个人踩同一个坑,成本还是你的。

验证用真实数据走一遍,测试数据太干净,边界情况根本碰不到。

处理上按这个顺序:解析域名拿到 IP 再判断 私网和回环段直接拒绝;只允许 http 和 https 禁掉 file gopher dict 这些协议;请求发出去后不跟随跳转 每一跳都重新校验;抓取服务放到独立网段 出网只放行白名单域名。

改完只确认一件事:再传 127.0.0.1 和 169.254.169.254 都返回参数错误 内网日志里没有这条请求。

作者 9823189