# 背景说明

OP 从 2018 年开始做了一个爬虫项目,从 2018 年持续维护到现在。
爬虫项目里面使用 tensorflow 训练了一个验证码识别器,从 2018 年以来,验证码识别器一直保持很高的准确率(>99%),但是从 2024 年 10 月 17 日开始,被爬的系统开始频繁报错“验证码错误”异常,最开始我以为是被爬系统加强了反爬策略,于是重新采集了 2w 张验证码,打上标记之后重新训练了一个模型,验证集成功率>99%之后将新的模型部署上去了,但是被爬系统依旧频繁报错“验证码错误”。
于是我开始具体的分析整个请求链路,发现这个事情似乎没有这么简单。

# 爬虫链路图示

![]( https://i.imgur.com/cvdFbCt.png) 在整个链路中,我将不同的服务器分别命名为 A 、B 、C 。

1. 其中 A 就是爬虫需要爬取的业务系统,这个系统是一个外包项目,可能很长时间才改动一次( 21 年改过一次版,虽然接口有细微变化,但是整体交互逻辑与以前项目差别不大,因此我们花了几天时间就完成了爬虫的全部功能适配)。A 使用 Cookie 进行会话管理,技术栈从接口看似乎是 ASP ,主要针对电脑用户,因此在打开页面的时候就会生成 Cookie ,登录成功之后 Cookie 一般不会变化(更多细节我们也不是很了解)。
2. 业务系统 A 藏在一个大内网之中,内网提供了深信服零信任平台 Atrust 的方式给非内网用户使用,只需要在自己电脑上连上 Atrust 并登录对应账号就可以直接访问业务系统 A 了。
3. Atrust 客户端以前我们是专门开了一台 Windows 服务器上面运行然后再通过 Nginx 将接口反向代理给其他服务器使用,从去年开始我们发现了一个将 EasyConnect 或者 Atrust 运行到 Docker 中的项目(项目地址: https://github.com/docker-easyconnect/docker-easyconnect ),因此我们将 VPN 从 Windows 服务器上迁移到了 Linux 服务器中,docker-atrust 在完成账号登录之后通过 tinyproxy 向外暴露 http 代理和 socks 代理。
4. 代理服务器 B 是使用 go 开发的服务,具体技术栈为 gin+标准库 http 包,加上 orirawlings/persistent-cookiejar 库实现 cookie 的持久化,gin 暴露一个统一代理接口,客户端发送过来的请求需要将用户标识、请求 Uri 以及访问需要使用代理信息设置到 Header 中,gin 收到请求之后根据用户标识和代理信息生成不同的 Cookie 存放路径,并且创建一个专用的 HttpClient ,与用户标识、代理信息 一起存储到 Map 中,后续相同用户标识再请求时直接从 Map 中获取 HttpClient 发送请求。
5. 代理服务器 B 使用上述的方案将来源于业务系统 A 的 Cookie 信息完全对其他服务隔离,这样业务服务器 C 需要获取业务系统 A 的返回数据时,只需要设置一个用户标识就可以直接进行请求了,不用再额外处理 Cookie 的设置、更新、删除等操作。
6. 业务服务器 C 上运行的是爬虫执行的具体逻辑,程序通过代理服务器 B 间接访问业务服务 A ,然后分析返回的数据并进行处理。

# 情况说明

- 出现大量的“验证码错误”报错的当天,代理服务器 B 、业务服务器 C 均没有任何改动,网络环境也没有任何改动,大量报错是突然开始出现的。

- 从表现来看,似乎是业务系统 A 增加了反爬的相关验证;但是我花了几个小时的时间对业务系统 A 在浏览器环境中请求的接口进行分析,并没有找到明显的痕迹证明业务系统 A 有过变更,依旧是使用“获取页面”、“获取公钥”、“获取验证码”、“识别验证码”、“登录”这些接口就完成了用户账号的登录。

- 我在**另外一台 Windows 服务器**上使用 Atrust 登录了相同的 VPN 账号,因为将程序对接过来需要处理网络相关的问题,所以我在服务器的 Edge 浏览器上直接进行**人肉测试**,打开页面、输入账号密码、登录,整个过程和以前一样,没有出现任何问题,**直接登录上了**。此时,原来通过 Docker 部署的 Atrust 依旧在处理来自线上的请求,并且持续报错“验证码错误”。

- 然后我调整了网络,将 Windows 云服务器直接在公网开放端口,并运行了 CCProxy 来暴露代理,在云服务器安全组中将代理服务器 B 加入到白名单中,这样代理服务器能够使用 Windows 云服务器的公网 ip 加上 CCProxy 的代理端口(808)就能实现与 Docker-Atrust 相似的功能。

- 接着,我调整了灰度设置,将线上的流量从原来的 Docker-Atrust 中**全部**切换到 Windows 云服务器。观察业务服务 C 一段时间后,业务服务 C 依旧在报错“验证码错误”。**此时,我再次打开 Windows 云服务器的 Edge 浏览器,重新运行之前测试过、正常的流程:打开页面、输入账号密码、登录,奇怪的现象出现了,网页报错“验证码错误”、“用户名或密码错误”**

- 这个奇怪的现象令我十分困惑,具体原因如下:

  - 如果是业务服务器 C 或者代理服务器 B 的问题,那么我在 Windows 云服务器上使用 Edge 浏览器应该依旧正常登录才对;
  - 如果是业务系统 A 的增加了反爬策略导致的问题,那么在 Edge 浏览器中应该报一个固定的错误,例如:“运行环境错误”、“检测到爬虫”之类的,不应该在“验证码错误”、“用户名或密码错误”中随机横跳;
  - 如果是因为代理服务器 B 持久化的 Cookie 逻辑存在导致用户的 Cookie 被错误复用,那么在 Edge 浏览器登录所使用的 Cookie ,代理服务器 B 理论上是永远拿不到的,因为从一开始它们的会话就是**隔离**的;
  - 除非,Atrust 把本应该属于 Edge 的 Cookie 返回给了代理服务器 B ,因为它们使用了相同的登录帐号?或者业务系统 A 做了这个十分离谱的事情?

  



带着上面的疑惑,我测试了多次 Edge 浏览器的登录,大多数情况下报错“验证码错误”、“用户名或密码错误”,如果我在提前输入好账号密码之后,快速多次点击验证码(触发验证码刷新),然后快速输入验证码并点击登录,就能够正确的登录进去。但是在登录后自动跳转的主页中报错“用户会话已注销”之类的提示。

此时夜已经很深了,我就将线上流量切回了 Docker-Atrust ,然后再次在 Windows 云服务器上 Edge 浏览器测试登录,此时它**正常**了。

😢

# 求助

这几天的时间里面,我每天都在想这个奇怪的现象,Edge 浏览器与爬虫程序的交叉点是从 Atrust 开始的,如果爬虫程序有问题应该不会影响 Edge 浏览器的 Cookie 与会话,既然影响了说明问题不是出在代理服务器 B 以及业务服务器 C ,而是 Atrust 往上的东西。

我甚至怀疑是 Atrust 存在 bug 导致了不同 Cookie 的请求被混合然后返回了错误的数据,或者是 Atrust 存在一个类似“连接复用”的功能?将不同 Cookie 的请求强行使用了相同的连接然后导致串会话?

我已经尝试修改了爬虫程序,在业务服务器 C 中,每次调用代理服务器 B ,都加上一个时间戳参数,用来确保每次请求的 Uri 均不相同(同一时间请求同一个接口有很小概率相同),问题没有得到解决,也没有肉眼看出来有任何的改善。

也花了时间翻了 Atrust 的一些功能说明和论坛,没有明确找到 Atrust 有这种“连接复用”的功能。

感谢大家花了这么多的时间看到这里,希望大家能够帮我分析分析,看看是不是我的排查思路哪里有问题?或者是 Atrust 的什么相关功能防止了我这种请求方式?

我已经实在是没辙了😢
举报· 33 次点击
登录 注册 站外分享
1 条回复  
返回顶部