先看现象。开放平台允许用户填回调地址,安全扫描发现填 http://169.254.169.254/latest/meta-data/ 也能保存并触发,服务端从内网发起请求,返回内容被写进了回调日志,云主机的临时凭证差点被读走。

真正麻烦的地方在于,几个原因的现象几乎一样。回调地址没有做协议与目标地址校验。少数情况下是没有拦截私有网段、回环地址与元数据地址。

另外,校验发生在保存时,触发时没有二次解析。

少数情况下是DNS 重绑定可以在校验后把域名解析到内网 IP。

复现一次对元数据地址的请求

curl -s -m 3 http://169.254.169.254/latest/meta-data/ -o /dev/null -w '%{http_code}\n'

随后在保存时解析域名并判定网段

python -c "import ipaddress;print(ipaddress.ip_address('10.0.0.8').is_private, ipaddress.ip_address('169.254.169.254').is_link_local)"

触发前再解析一次并比对

python -c "import socket;print(socket.gethostbyname('example.com'))"

出口侧只放行公网白名单端口

python -c "print({'allow_scheme':['https'],'deny_cidr':['10.0.0.0/8','169.254.0.0/16','127.0.0.0/8']})"

怎么算真的好了,看的是同一批现象。保存内网地址时直接报错,触发阶段解析到私有网段也会被拒,正常公网回调仍然成功且延迟没有变化。

补一句。回调地址是用户可控的出口请求,协议、域名解析、目标网段三层都要校验,只在保存时查一次挡不住 DNS 重绑定。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。

作者 9823189