Google Search Console 发来一封“kafka.immersivepoints.com 新 owner”的邮件。
问题是,immersivepoints.com 的站长并没有这个子域名,也没有把它交给别人。后来他又看到 grandbet、hd 等子域名相关提示,页面内容指向博彩、疑似诈骗方向。
这件事容易被误读成账号被盗。更准确的判断是:站长把 *.immersivepoints.com 这类通配符 DNS 指向了 GitHub Pages,陌生人又在 GitHub Pages 仓库里绑定了未验证子域名。两边一接上,域名的空房间就被别人住进去了。
这不是一个玄学安全事故。它更像一个很典型的“省事配置”反噬。
问题是怎么暴露的:Search Console 先响了
作者原本只用 immersivepoints.com 托管一个 GitHub Pages 静态页面,用来展示 3D 和 VR 点云可视化项目。
为了让 www 等地址访问更方便,他在 DNS 里配置了 *.immersivepoints.com。这个配置的意思是:只要是 immersivepoints.com 下面的子域名,默认都指向 GitHub Pages。
麻烦就在“默认都指向”。
当第三方在自己的 GitHub Pages 仓库中写入 CNAME,比如 kafka.immersivepoints.com,而 DNS 又确实把这个地址导向 GitHub Pages,页面就可能被 GitHub Pages 接住。作者看到的 Search Console “新 owner”邮件,成了异常暴露的关键线索。
这里有一个现实限制:相关仓库可能是私有仓库。作者不一定能直接看到仓库内容,也不一定能按普通开源仓库的方式举报到具体代码页。
这对个人站长很要命。你可能没有丢密码,也没有被注册商劫持,但你的域名信誉已经被拿去给陌生页面背书。
| 环节 | 发生了什么 | 风险点 |
|---|---|---|
| 原始用途 | immersivepoints.com 托管一个 GitHub Pages 静态页 | 需求本身很普通 |
| DNS 配置 | *.immersivepoints.com 指向 GitHub Pages | 未使用子域名也被一起开放 |
| 第三方操作 | GitHub 仓库 CNAME 绑定 kafka.immersivepoints.com 等地址 | 可能来自作者看不到的私有仓库 |
| 暴露线索 | Google Search Console 发出“新 owner”邮件 | 搜索工具变成了早期告警 |
| 事后发现 | GitHub Pages 有自定义域名验证功能 | 入口在账户设置,不在仓库 Pages 设置页,容易漏掉 |
技术根因:不是所有 GitHub Pages 都危险,是这个组合危险
子域名接管不是新问题。安全社区长期把“悬空 DNS”列为常见风险:DNS 还指向某个平台,但平台侧的资源控制权、授权关系或绑定状态没有跟上。
这次的关键组合有三个条件。
- 站长配置了 `*.immersivepoints.com` 这类通配符 DNS。
- 通配符记录指向 GitHub Pages。
- 第三方仓库能绑定这些未验证、未授权的子域名。
少掉其中一环,风险就会小很多。比如只配置明确的 www.immersivepoints.com,就不会把 kafka、grandbet、hd 这类未计划使用的子域名一起送到同一个入口。
也要说清楚,GitHub Pages 并不是完全没有域名验证机制。GitHub 实际提供自定义域名验证,用户可以通过添加 TXT 记录来证明域名所有权。
问题在入口和默认体验。
作者事后才发现,这个验证功能在账户设置里,而不是仓库的 GitHub Pages 设置页。很多人配置 Pages 时,动作路径是“仓库设置 -> Pages -> 填自定义域名”。如果关键安全开关藏在另一个地方,就很容易被当成可选项漏掉。
对比 Netlify、Vercel、Cloudflare Pages 这类静态托管平台,行业共识已经比较清楚:自定义域名不是单纯的“填个地址”。它是权限边界。
平台不一定要把所有历史配置一刀切拦掉。现实约束也存在:很多老项目、迁移项目、自动化部署都依赖现有流程。但至少在仓库 Pages 设置页,应该把“未验证域名”的风险提示做得更硬。更稳的做法,是对同一主域名下跨账号绑定子域名增加授权校验。
这不是要求平台替用户管理 DNS。是不要让一个用户的通配符记录,轻易变成另一个用户的免费入口。
个人开发者和小团队该怎么改
最受影响的不是大公司安全团队,而是个人项目、开源演示站、小团队官网。
它们常用 GitHub Pages,因为免费、简单、不用管服务器。也常把 DNS 配得很宽,因为一开始只是想省事:www 能访问,临时页面能挂上,后面再说。
但 DNS 的“后面再说”,经常会变成安全债。
如果你正在用 GitHub Pages 绑定自定义域名,动作可以很具体:
| 你现在的情况 | 建议动作 | 影响 |
|---|---|---|
只需要主域名和 www | 删除 *. 通配符,只保留明确记录 | 减少陌生子域名被接管的入口 |
| 确实需要通配符子域名 | 完成 GitHub Pages 自定义域名验证,按文档添加 TXT 记录 | 把域名所有权补上 |
| 多人维护 DNS 和仓库 | 把 DNS 记录、Pages CNAME、Search Console owner 列入交接清单 | 避免离职、迁移后留下悬空配置 |
| 收到异常 Search Console 邮件 | 立刻核对该子域名是否由自己创建,检查是否有未知索引页面 | 把搜索侧告警当成安全信号 |
小团队还应该把这件事写进上线流程:谁能改 DNS,谁能改 Pages 自定义域名,谁负责核对 Search Console。这个流程不复杂,但能挡住很多“看起来不是漏洞”的漏洞。
接下来真正该看的,不是 GitHub 会不会发一篇解释文章,而是两个更具体的变量。
一个是 GitHub 是否把账户级域名验证前置到仓库 Pages 配置流程里。用户填 CNAME 时,如果域名未验证,页面就应该给出明确阻断或强提醒。
另一个是 GitHub 是否限制跨账号绑定同一主域名下的任意子域名。尤其是当主域名已经被某个账户验证后,其他账户再绑定该主域下的子域名,应该有更严格的授权路径。
如果这两点不变,类似事故还会继续出现。不是每次都会被 Search Console 及时提醒,也不是每个站长都会盯着邮箱里的 owner 变更通知。
回到开头那封邮件,它真正提醒的不是 kafka 这个子域名有多特殊,而是通配符 DNS 的边界太容易被低估。你以为自己只是给访问留了方便,别人看到的可能是一个可以挂页面的入口。
