外链头像安全实验室

允许用户输入图片 URL 作为头像,看起来人畜无害——直到它指向的服务器开始作恶。打开下面任意场景开关,看你自己的浏览器是怎么被这个"头像"耍的。

你的专属测试头像

服务端为你生成了一个唯一的 UUID,下面这个 <img> 标签直接外链到该地址。开启右侧任意开关后,刷新头像即可看到它"变脸"。

my avatar
加载中…
我的 token: —
头像 URL: —

提示:新标签打开是 top-level navigation,不受跨域子资源限制,能看到 401 Basic Auth 弹窗 / 302 真实跳转——而 <img> 加载会被浏览器静默拦下。

攻击场景开关(单选)

同一时刻只能开一个场景,因为同一张图无法既是"恐怖图"又"重定向"又"401"。每张卡上的徽章告诉你:至今有效 = 浏览器没防, 2018 后被压制 = 现代浏览器拦下子资源加载、但 top-level 仍中招。

这张头像悄悄收集了什么

即使头像内容是正常的,仅仅是被浏览器加载这件事,就让攻击者拿到了你的 IP、User-Agent、Referer。下面是服务端真实记录到的访问日志:

0 条记录
时间 IP User-Agent Referer
暂无访问记录,刷新头像看看?

风险全景

把"用户 URL 当头像"这件事拆开看,至少有这些坑:

钓鱼 401 弹窗

服务端返回 401 + WWW-Authenticate: Basic,浏览器立刻弹原生账号密码框——伪装成「请登录以查看头像」,骗用户输入主站凭据。

重定向到攻击载荷

URL 看着是 .jpg,实际服务端 302 跳到 http://localhost:8080/admin?...,命中内网管理后台、Redis、云元数据等——SSRF 的入门姿势。

内容随时被替换

图片在别人服务器上,今天是正常头像,明天可能换成血腥/色情/政治敏感图片——平台口碑被一张 <img> 拖下水。

访客信息泄露

每个浏览过该头像的用户都把自己的 IP、UA、Referer 上交给攻击者,方便针对性钓鱼或者画像建模。

流量炸弹 / 慢响应

10MB 一张的"头像"或永远不返回的连接,把你的页面、CDN、流量包一起拖下水。

外链失效破图

第三方服务挂了,你的用户列表瞬间一堆碎图,体验崩盘。

正确做法

核心原则只有一条:永远不要直接信任用户提供的 URL。把它当作"原始素材",做一道完整的清洗工序:

  1. 协议白名单:只允许 https://,拒绝 http / file / data / javascript / gopher。
  2. SSRF 防护:DNS 解析后校验 IP 不在 127.0.0.0/8、10/8、172.16/12、192.168/16、169.254/16(云元数据)等保留段。
  3. 禁用重定向:服务端拉取时关闭 follow redirects,或对每一跳都重新做 IP 校验。
  4. Content-Type + Magic Number 双校验:响应头说 image/jpeg 不够,还要校验文件头 FF D8 FF。
  5. 大小 / 尺寸限制:超过 5MB 或 4096×4096 直接拒绝。
  6. 解码重绘:用 ImageIO / sharp 解码后重新编码输出,剥离 EXIF、隐写 payload、SVG 里的脚本。
  7. 内容审核:接黄反/暴恐/版权检测,留好申诉与回退路径。
  8. 转存自家 CDN:以自有域名对外服务,从此与第三方 URL 一刀两断。
用户 URL 协议白名单 DNS + IP 校验 拉取(无重定向) Magic Number 大小校验 解码重绘 内容审核 自家 CDN