Backend

开启代理工具后,爬虫的安全检查误把正常网站当成内网地址,排查记录

1747 字约 6 分钟

摘要本地爬虫开启 Clash 等代理工具的 Fake-IP 模式后,27 个大学教师主页全部被 SSRF 校验拒绝。本文介绍如何在不放松安全边界的前提下,处理透明代理与内网防护之间的冲突。

在 Auto Email Sender 的智能抓取模块中,有一条严格的安全要求:防范 SSRF(服务端请求伪造)。

抓取目标中有些链接是大模型从网页里推荐的,因此必须防止恶意网页把爬虫引到内网:比如探测用户的 127.0.0.1:8080、读取内网路由器配置,或扫描公司局域网中的 NAS。

为此,系统在每次发起 HTTP 请求前,都会先对域名做 DNS 解析,拒绝任何指向私有 IP(如 10.0.0.0/8、192.168.0.0/16、127.0.0.1)的请求。即使发生了 302 重定向,最终落地的 IP 也要重新检查。

这套逻辑本身是标准的。直到有一位同学报告了一个奇怪的问题:他在软件中输入了 27 个 985 高校的教师主页,任务一启动,控制台就出现了大量报错:

“请求被拒绝:URL 不允许指向本机、内网或不可解析地址。”

27 位正常的教授主页,一个字节都没能抓到,全部被安全检查拦截了。

什么是 SSRF 和私有保留网段?

SSRF(Server-Side Request Forgery)是一种常见的安全漏洞。攻击者诱导服务端向内网地址发起请求,从而绕过防火墙探测内部资源。因此,成熟的网络库通常会拦截 10.0.0.0/8、172.16.0.0/12、192.168.0.0/16 以及 127.0.0.1 等私有保留地址。

原因是 Clash 的 Fake-IP

在普通浏览器中打开这几个网址,都能快速加载,没有任何问题。

我在本地运行单元测试,用 Python 的 socket.getaddrinfo() 解析了出问题的大学域名。

输出的 IP 是 198.18.0.23。

这个 IP 段正好触发了安全规则。

原因是:用户电脑上开着代理软件(如 Clash / Mihomo),并且启用了“增强模式 / 系统代理”的 Fake-IP 功能。

通俗比喻:游乐园里的虚拟排队手环

为什么代理软件会返回一个不存在的 198.18.x.x 地址? 想象你去一个热门游乐园:

  • 常规流程:你需要自己去问清楚项目是否开放、真实的位置在哪(向 DNS 服务器解析真实的公网 IP);
  • Fake-IP 模式:入口的工作人员(代理核心)直接给你一个写着 023 号 的手环(虚拟 IP),告诉你“不用管它在哪,拿着这个手环走专用通道,我会带你过去”。

对游客来说,只要能玩到项目,手环编号无所谓;但对园区的安保(SSRF 防御)来说,它只认正规的门牌号。看到公网地图上查不到的编号,安保会认为这个人持有伪造证件,直接拦下。

什么是代理的 Fake-IP 模式?

传统的代理转发需要先把域名交给本地 DNS 解析,然后连接真实的公网 IP。 在 Fake-IP 模式下,为了加快网络握手并防止 DNS 污染,代理程序会拦截所有 DNS 请求,并从 RFC 2544 规定的基准测试保留段 198.18.0.0/15 中分配一个虚拟 IP 返回给操作系统。 应用程序拿这个虚拟 IP 发起 TCP 连接,流量被系统驱动透明地转交给代理核心,代理核心再根据原始域名去连接真实的服务器。

从操作系统的角度看,这只是代理软件的一种工作方式。但从安全模块的角度看,198.18.* 并不是合法的公网可路由地址,而且属于保留的私有段,因此会被拒绝。

直接放行的做法不可取

找到原因之后,最直接的改法是:“既然是代理导致的,那就把 198.18.0.0/15 加入白名单,或者检测到系统开了代理就直接关闭 SSRF 检查。”

这种做法很危险。

攻击者完全可以在网页中构造一个解析到 127.0.0.1 的域名。如果因为开了代理就无条件放行,恶意页面就能借助爬虫探测用户的本地服务,抓到的内网数据甚至可能被送给大模型,进一步泄露出去。

安全检查不能因此放松。

需要区分的是两种情况:

  • 情况 A: 域名在公网上确实是合法的网站,只是在本地被代理映射成了 Fake-IP;
  • 情况 B: 域名本身就指向私有网络或回环地址,属于恶意地址。

为此,我们重新设计了校验流程:

1. 发起校验 ──> 使用系统默认 DNS 解析 (得到 IP_1)
2. IP_1 为 127.0.0.1 / 192.168.* ──> 直接拒绝
3. IP_1 位于 198.18.* (疑似 Fake-IP 段) ──> 启动【可信公网 DNS 交叉复核】
   └──> 通过独立的 223.5.5.5 / 119.29.29.29 直接查询公网权威 DNS (得到 IP_2)
4. 公网复核确认为合法公网 IP ──> 判定为正常的代理流量,放行
5. 公网复核仍为私网地址或解析失败 ──> 直接拒绝
6. 发生 302 重定向 ──> 对跳转后的地址完整重新执行第 1 到 5 步
交叉复核的好处

这个方案既不需要维护学校域名白名单,也不会在开启代理时放松安全要求。只有当本地 DNS 的结果带有代理特征时,才会通过独立的通道向公网确认域名的真实地址。

修复只做了一半

修改之后,我在本地写了单元测试,用那几个教师主页做了验证,校验全部通过,抓取也正常。

新版本发布不到两天,又有人报告了同样的问题:

“我用的就是最新版本,开着代理抓取,还是被内网拦截?”

我按照用户的操作流程逐步回放,才发现问题所在。

Auto Email Sender 的抓取流程有两个入口:

  • 入口 1(个人主页): 直接抓取某位老师的个人主页;
  • 入口 2(教师列表): 先抓取学院的列表页,再抓取分页,最后抓取每位老师的详情。

我上一次的修复,只在入口 1 的校验函数中启用了公网复核。 而用户最常用的入口 2 列表提取器,仍在使用旧的严格模式。

测试用例只覆盖了单人主页的抓取,所以测试全部通过,但主要的业务路径上仍有遗漏。

总结

这次排查不仅解决了 Fake-IP 与安全规则之间的冲突,也统一了整个系统的出站网络检查:

网络访问场景旧版行为修复后的行为
公网域名被代理映射为 Fake-IP误判为私网并拦截经公网 DNS 复核确认后放行
直接输入私网 IP(如 192.168.1.1)拒绝访问继续拒绝访问
公网域名跳转到内网地址存在被绕过的风险对重定向的每一跳重新校验并拦截
列表页、分页、正文、OCR 多个入口规则不统一,各自为政全部经过统一的安全检查

现在的桌面应用需要面对各种网络环境,包括 VPN、透明代理、TUN 虚拟网卡和自建 DNS 服务。

在编写爬虫或任何需要主动对外访问的系统时:

  • 安全检查不能因为网络环境复杂而放松;
  • 用外部权威源做交叉校验,是识别本地网络映射的可靠方法;
  • 修复安全问题时,要梳理完整的业务链路,避免只修一个入口、漏掉其他入口。

评论