深信服 Atrust 篡改了我的 Cookie 吗?求助一个可能关于深信服 Atrust 的问题

139 天前
 Mystery0

背景说明

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

爬虫链路图示

在整个链路中,我将不同的服务器分别命名为 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 ,然后分析返回的数据并进行处理。

情况说明

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

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

😢

求助

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

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

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

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

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

我已经实在是没辙了😢

2372 次点击
所在节点    问与答
35 条回复
tomatocici2333
138 天前
@Mystery0 #19 返回整个 html 很正常。你都说了是老系统,对方有可能是 jsp
Mystery0
138 天前
@tomatocici2333 #21 如果是深信服拦截并处理的,返回的就不是 html 了,因为深信服不知道正方的 html 有什么东西。因此,如果是深信服检测并拦截了,那也只能是将检测结果给业务系统也就是正方,让正方来报错返回正方的 html
for1shot
138 天前
@Mystery0 #19 可能是我 ”封堵“一词表述不当,造成了误解。
封堵并不一定会关闭整个 tcp 会话。
封堵有两种模式,一种是监测到异常的 tcp 流量之后,伪造一个 tcp close 报文,从而关闭整个 tcp 的对话,这种情况下会报 404 ,或者其他什么错误,表现为看不到 html 。这种是以流为单位的管理策略。
还有一种是深度包检测,是以数据包为单位进行管理,也就是监测到异常数据包之后,比如发现特定 cookie 字符串的数据包,仅仅擦除该数据包内的 cookie ,然后继续发给服务端。这就可能会导致:可以看到 html 返回,但是由于服务端收到的包被篡改了,就返回账号密码错误。
NoOneNoBody
138 天前
“大量”是个虚词
先说有没有成功的,还是全部都出错
如果并非全部出错,成功的数量也不少,不是零零星星几个的话,代码应该没问题,更多是链路中间的问题

现在的 web 服务器,没有反爬的话,都不像话
你这里写的都是些很基础的爬虫知识,也不晓得你有没有做高级抗反爬
现在很多都是 cdn 反爬,例如 cf 的五秒盾,很难破,基本需要降频,高频就需要不断变换 ip ,另外还有客户端生成 token 这些,都需要让客户端抗指纹

这里还有一个重点你没说,既然是需要登录,是有大量帐号么?还是帐号都是用户自己的?
如果都是贵司提供,不断复用,被风控那基本都是秒级的事,能爬几年真是不可思议
Mystery0
138 天前
@for1shot #23 第二种确实有可能,也正好能解释为什么返回 html ,我想想办法按这个思路验证一下
Mystery0
138 天前
@for1shot #23 这个情况是 10.17 那一天突然开始出现的,倘若真是这个原因的话,我倾向于认为是 负责管理 Atrust 的管理人员,在那一天发现了 Atrust 有这个功能,然后给打开了
for1shot
138 天前
@Mystery0 #26 老哥要是解决了,说说解决思路哈
tomatocici2333
138 天前
@Mystery0 #22 大概率是 A 出了问题
Mystery0
138 天前
@NoOneNoBody 有成功的,甚至现在都有成功的,因为正方提供的是教务数据,也就是课表之类的东西,学生上课时间是固定的,所以几年来只要是上课的日子都会在固定的时间点前后产生大量的请求。

从几天的请求响应监控来看,基本是上课时间前 20 分钟左右达到请求峰值,然后出现大量失败的请求,失败率在 50%甚至更高,(业务服务 C 对每一个返回给客户端的请求都有响应码和错误码的监控),上课之后请求量减少,成功率增加,大概是 75%-80%的成功率。等到一天的课程结束,特别是凌晨的时候,请求量特别少,这个时候成功率几乎大于 90%。

正方教务系统它是部署在学校机房的,往外没有 CDN (因为不提供公网访问,仅在校园网访问)
登录正方的账号都是用户自己的,登录 Atrust 的账号是我找学生借的(只有一个)
NoOneNoBody
138 天前
@Mystery0 #29
这样说就比较明显了,要么就是对方反爬,要么就是对方机器也抗不住了

整体看下来,你们不是一个主动爬虫,就是不会游走爬取“未知”的内容,更像是个数据代理,把客户请求及爬取返回内容优化?
如果内容有大量重复,建议按规则做缓存,减少爬取次数
当然,缓存要准确,不然就相当于你们“制造”了错误数据,信用断崖下降了;而且缓存的内容涉及隐私的话,还要凭良心“加密”才缓存
Mystery0
138 天前
@NoOneNoBody #30
更像是个数据代理,把客户请求及爬取返回内容优化?
————————
对,是做的这个


如果内容有大量重复,建议按规则做缓存,减少爬取次数
————————
现在服务端只处理数据,不会主动存储,客户端做了数据落库的缓存,但是也提供了“刷新”缓存数据的功能,每天第一次打开 APP 的时候会执行登录逻辑然后获取数据,这样做的原因也是因为以前出现过显示错误数据的情况导致了一些问题
NoOneNoBody
138 天前
@Mystery0 #31
不是这个意思
例如三个用户都请求相同的 A 页面(同一个课程表什么的),但在服务器方看来,就是贵司一个 ip 对 A 请求了三次;所以这三个 A 的请求,最好能减少到一次,另两个以缓存返回给用户
Mystery0
137 天前
@defunct9 #11 @tomatocici2333 #14 昨天下午我针对 A 做了多次账号登录的测试,使用 docker-atrust 提供 vpn 环境,然后在 Mac 上使用不同浏览器登录不同的账号,没有发现 A 系统有踢出的相关逻辑,应该和 A 关系不大


@for1shot #23 我今天( 26 号)下午做了很久的测试,用了 Reqable 抓包仔细对比了浏览器发送的请求头信息和程序设置的请求头,浏览器发送的头没有发现非常明显的针对风控的标识,但是程序的请求头有些过于死板了(从打开页面到最终请求登录接口,都十分的“标准”,时间戳参数要么都有,要么都没有,部分在浏览器端通过 js 发起的请求 [带有 X-Requested-With 头] 没有带上相对应的头),虽然这些“特征”不一定被 A 系统识别并检测了,我还是依次对比之后补上了一些请求头参数,现在从 Reqable 抓包来看,请求更“像”浏览器发起的了。

最后说一下关于 Atrust 部分,从我下午的测试情况来看,感觉出现问题的地方是和 Atrust 有关系,但是不知道是如何实现的:刚开始的时候我在通过浏览器和程序依次发送不同账号的登录请求,以此来对比两种请求方式的不同点并针对性的进行修改(具体差异见上一段)。持续了比较长的一段时间之后,就出现了一个明显异常的情况:这个时候在浏览器上我直接访问页面能够显示登录页面,但是输入任何账号(我本地测试用的是 3 个不同的账号)进行登录均无法登录,并且 [ [不再显示错误原因] ] !!!我保证测试账号的密码没有输错,验证码也没有输错,并且我试了很多次,都是这样的现象。
跟踪了一下这一种新的现象,具体表现为:
1.通过浏览器加载登录页面 GET /login.html (仅作说明,具体路径不是这个),无论是直接访问域名(未登录情况下会 302 到登录页面)还是直接访问登录页面
2.浏览器打开页面会正常显示,同时自动获取公钥( GET /public.html ),自动加载验证码( GET /kcaptcha )
3.在浏览器上输入账号、密码、验证码之后,页面正常发起登录请求( POST /login.html )
4.POST 请求返回 302 重定向状态码,但是 Location=/ (以前登录失败时返回的是 200 状态码,并且响应体内容位 html ,html 中带有错误原因)
5.因为 302 到了/,然后又走了一次第一步的流程,页面再自动 302 到/login.html ,因为是 302 过去的,所以是正常 GET /login.html ,也就没有错误信息了

今晚在家里的 windows 机器上,装了个 windows11 的虚拟机,登录上 Atrust 之后将代理服务器 B 部署进去,然后本地启动业务服务 C ,跑了三个账号的登录,没有发现什么问题(没有问题可能是特征暂时未识别出来,也可能是请求量太少没有达到并发的量),至少没有出现下午那种“不显示原因的直接失败”的情况了。

说说最终的结论吧,现在呢大概是能确定应该和 Atrust 有点关系,可能是 Atrust 检测到访问 A 系统的请求经过了代理( docker-atrust 里面用的 tinyproxy ,可能带了某些特征 [例如请求头] ),也可能是请求参数过于“标准”触发了 Atrust 的什么网络策略,然后 Atrust 对应该正常发送给 A 的数据包做了一些修改(不知道具体的修改内容)导致 A 接收数据不完整从而登录失败。
斗智斗勇了几天呢,今晚最后再上一次代码修改看看有没有什么改善,如果还是不行的话,就只能想办法绕过 Atrust 直接请求 A 了(想办法在大内网环境里面弄一台机器通过 tailscale 组网来直接提供接口代理),或者和 A 谈一下,被官方收编了算了……
defunct9
134 天前
@Mystery0 最新结果是什么呢?很好奇
Mystery0
134 天前
@defunct9 #34 打算按收编来谈了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1083548

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX