允许用户输入图片 URL 作为头像,看起来人畜无害——直到它指向的服务器开始作恶。打开下面任意场景开关,看你自己的浏览器是怎么被这个"头像"耍的。
服务端为你生成了一个唯一的 UUID,下面这个 <img> 标签直接外链到该地址。开启右侧任意开关后,刷新头像即可看到它"变脸"。
—
—
提示:新标签打开是 top-level navigation,不受跨域子资源限制,能看到 401 Basic Auth 弹窗 / 302 真实跳转——而 <img> 加载会被浏览器静默拦下。
同一时刻只能开一个场景,因为同一张图无法既是"恐怖图"又"重定向"又"401"。每张卡上的徽章告诉你:至今有效 = 浏览器没防, 2018 后被压制 = 现代浏览器拦下子资源加载、但 top-level 仍中招。
即使头像内容是正常的,仅仅是被浏览器加载这件事,就让攻击者拿到了你的 IP、User-Agent、Referer。下面是服务端真实记录到的访问日志:
| 时间 | IP | User-Agent | Referer |
|---|---|---|---|
| 暂无访问记录,刷新头像看看? | |||
把"用户 URL 当头像"这件事拆开看,至少有这些坑:
服务端返回 401 + WWW-Authenticate: Basic,浏览器立刻弹原生账号密码框——伪装成「请登录以查看头像」,骗用户输入主站凭据。
URL 看着是 .jpg,实际服务端 302 跳到 http://localhost:8080/admin?...,命中内网管理后台、Redis、云元数据等——SSRF 的入门姿势。
图片在别人服务器上,今天是正常头像,明天可能换成血腥/色情/政治敏感图片——平台口碑被一张 <img> 拖下水。
每个浏览过该头像的用户都把自己的 IP、UA、Referer 上交给攻击者,方便针对性钓鱼或者画像建模。
10MB 一张的"头像"或永远不返回的连接,把你的页面、CDN、流量包一起拖下水。
第三方服务挂了,你的用户列表瞬间一堆碎图,体验崩盘。
核心原则只有一条:永远不要直接信任用户提供的 URL。把它当作"原始素材",做一道完整的清洗工序:
https://,拒绝 http / file / data / javascript / gopher。127.0.0.0/8、10/8、172.16/12、192.168/16、169.254/16(云元数据)等保留段。FF D8 FF。