前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >爬虫浏览器的Cloudflare五秒盾处理

爬虫浏览器的Cloudflare五秒盾处理

作者头像
mythsman
发布2022-12-13 16:08:26
4.4K0
发布2022-12-13 16:08:26
举报

背景

近期业务有不少涉及到国外的网站,本以为经受了和国内大量卷王公司对抗的考验之后,处理国外业务应该是降维打击才对。结果本地测试的时候的确很OK,但是一上线就发现全面飘红,多个不同业务同时出了 Cloudflare 著名的五秒盾

根据 Cloudflare 的说明,只要是使用 Cloudflare 的域名解析服务,默认都会自动“享受” 他家的一系列防护服务(尤其是 Javascript 防护)。具体特征就是会在/cdn-cgi/challenge-platform/ 下嵌入风控逻辑。他们会收集浏览器的一系列指纹,再根据后台大数据对比,计算出当前环境的可疑概率以进行风控。

原则上出现这个也无妨,毕竟五秒盾也只防第一次登录。就算 hCaptcha 不好自动化处理,先人肉处理下,后续复用统一份 Cookie ,只要控制好规模和频率,基本能满足业务需要。但是吊诡的在于:无论验证多少次,永远不会跳转回正常网页。(鬼知道我点了多少次小海豚和大熊猫)

一般来说,对于网页爬虫而言,遇到强力风控时,只要不是极其重要的业务,我们一般都是考虑从业务上更换策略,尽量不正面硬刚。但是用本地浏览器在匿名模式下访问时、在和线上使用相同代理IP的前提下,虽然也出了五秒盾,但是人肉点也是能正常滑过的。这说明他的风控策略本身应当并不强,或者说这看起来不像是一种反爬策略,而更像是一种 Bug 或是某种安全策略,并不像是无法解决的问题。于是就尝试处理了一下,果然发现了一些意料之外的坑。

环境

我们的工作环境是基于 cef 定制的有头浏览器。通过 cef 框架 hook 浏览器页面的 LoadStart, LoadEnd, LoadError 等事件,注入用于页面操作的纯 JS 脚本,再通过代理抓包获取数据。同时定制一些集群管理、任务管控、链路追踪等逻辑。内核基于的是 87.1.12+g03f9336+chromium-87.0.4280.88 的 Linux 版本,默认的 Chromium 启动参数大致有如下这些:

代码语言:javascript
复制
--disable-dev-shm-usage
--no-first-run
--disable-web-security
--disable-site-isolation-trials
--lang=zh-CN
--no-sandbox
--single-process
--disable-http2
--disable-gpu
--disable-sync
--allow-running-insecure-content
--ignore-certificate-errors
--proxy-server=localhost:8080
--user-agent="some user agent"

解决

解决的思路比较清晰,既然本地环境可以正常过风控、线上的环境不行,我们就先想办法在本地搭建类似线上的环境,先想办法复现出问题,再控制变量将二者环境参数不断接近,直到找到临界的问题点。

测试的时候尤其需要注意两点:

  1. 如果配置了用户目录或者缓存目录,一定要记得每次测试前都要删一下,防止影响结论。
  2. 每一次测试都要重复多次,否则很容易由于各种偶然原因影响结论。

这里省略枯燥的探索过程,直接记录多次尝试后的结论:(实测,以下配置缺一不可)

关闭 --single-process 配置

默认 Chromium 是多进程模式的。这里的多进程模式可以有两层理解:

  1. 窗口进程、渲染进程、GPU进程、工具进程分开;
  2. 不同站点页面进程分开;

进程分开的好处就是可以更方便的进程安全控制,但是代价就是整体内存占用会略高。

因此我们线上默认选择了单进程模式,本意是为了节省进程数从而节省内存,让单个机器能同时跑更多的任务。当然,这里说的单进程并不是只有一个进程,而是只有 zygote 一种进程。(参考 #single-process-mode

例如,打开百度,如果采用单进程模式,只会有四个进程:

代码语言:javascript
复制
myths@ubuntu:~$ ps -ef|grep myproject|grep -v myproject
myths      27250    3785 10 15:27 pts/1    00:00:05 /home/myths/Projects/myproject --url=https://www.baidu.com --single-process
myths      27253   27250  0 15:27 pts/1    00:00:00 /home/myths/Projects/myproject --type=zygote --no-zygote-sandbox --lang=en-US --user-data-dir=/home/myths/.config/cef_user_data
myths      27254   27250  0 15:27 pts/1    00:00:00 /home/myths/Projects/myproject --type=zygote --lang=en-US --user-data-dir=/home/myths/.config/cef_user_data
myths      27256   27254  0 15:27 pts/1    00:00:00 /home/myths/Projects/myproject --type=zygote --lang=en-US --user-data-dir=/home/myths/.config/cef_user_data

而如果使用默认的多进程模式,则会有八个进程:

代码语言:javascript
复制
myths@ubuntu:~$ ps -ef|grep myproject -v myproject
myths      27351    3785  9 15:29 pts/1    00:00:00 /home/myths/Projects/myproject --url=https://www.baidu.com
myths      27354   27351  0 15:29 pts/1    00:00:00 /home/myths/Projects/myproject --type=zygote --no-zygote-sandbox --lang=en-US --user-data-dir=/home/myths/.config/cef_user_data
myths      27355   27351  0 15:29 pts/1    00:00:00 /home/myths/Projects/myproject --type=zygote --lang=en-US --user-data-dir=/home/myths/.config/cef_user_data
myths      27357   27355  0 15:29 pts/1    00:00:00 /home/myths/Projects/myproject --type=zygote --lang=en-US --user-data-dir=/home/myths/.config/cef_user_data
myths      27378   27351  4 15:29 pts/1    00:00:00 /home/myths/Projects/myproject --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --lang=en-US --user-data-dir=/home/myths/.config/cef_user_data --shared-files=v8_context_snapshot_data:100 --field-trial-handle=0,i,4491148827631734197,7878804601012403413,131072 --disable-features=BackForwardCache
myths      27394   27357  0 15:29 pts/1    00:00:00 /home/myths/Projects/myproject --type=renderer --user-data-dir=/home/myths/.config/cef_user_data --first-renderer-process --lang=en-US --num-raster-threads=1 --renderer-client-id=5 --time-ticks-at-unix-epoch=-1669691342091293 --launch-time-ticks=102038976468 --shared-files=v8_context_snapshot_data:100 --field-trial-handle=0,i,4491148827631734197,7878804601012403413,131072 --disable-features=BackForwardCache
myths      27395   27357 35 15:29 pts/1    00:00:02 /home/myths/Projects/myproject --type=renderer --user-data-dir=/home/myths/.config/cef_user_data --lang=en-US --num-raster-threads=1 --renderer-client-id=4 --time-ticks-at-unix-epoch=-1669691342091293 --launch-time-ticks=102038982131 --shared-files=v8_context_snapshot_data:100 --field-trial-handle=0,i,4491148827631734197,7878804601012403413,131072 --disable-features=BackForwardCache
myths      27420   27354  2 15:29 pts/1    00:00:00 /home/myths/Projects/myproject --type=gpu-process --lang=en-US --user-data-dir=/home/myths/.config/cef_user_data --gpu-preferences=WAAAAAAAAAAgAAAIAAAAAAAAAAAAAAAAAABgAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAIAAAAAAAAAABAAAAAAAAAAgAAAAAAAAACAAAAAAAAAAIAAAAAAAAAA== --use-gl=angle --use-angle=swiftshader-webgl --shared-files --field-trial-handle=0,i,4491148827631734197,7878804601012403413,131072 --disable-features=BackForwardCache

使用单进程模式看似很美好,但是问题就是失去了多进程间的隔离,很多安全策略就失效了,浏览器的安全性就会下降很多。同时单进程模式下似乎也更容易出 bug,我在测试的时候发现单进程模式下的浏览器的确很容易出现一些 DeadLock 和 Coredump。

Cloudflare 或许通过某种方式测试出了单进程模式下安全性的问题,也或许是触发了单进程模式下的一些 Bug,导致风控页面无法跳转,具体方式还不清楚。

关闭--disable-site-isolation-trials 配置

添加这个配置的本意是方便进行跨域请求,但是据说这个需要跟 --disable-web-security--user-data-dir 一起使用才能生效(参考 StackOverflow)。但是实际上我测试下来,不加这个配置也能进行跨域访问,不太明白。

Cloudflare 似乎也能检测到这个参数引入后带来的问题,导致风控校验不过。原因也不明。

Chromium 内核版本尽量用较新的版本

众所周知,UserAgent 信息一定会被拿来进行大数据计算和风控识别,因此这个值的设置要尤其注意:

  1. UserAgent 里带的浏览器内核版本要尽量的新。长期不升级的浏览器显然是有问题的,况且内核较老的浏览器容易有未被修复的安全漏洞,可能会通不过检测。
  2. UserAgent 的值尽量和真实的内核版本一致。毕竟 UserAgent 声明的配置有时是会和其他配置互相应证的,如果不改全,很可能会被认为是恶意修改。不过,如果是 Linux 机器,还是建议不要用 Linux 的 UA,毕竟在 Linux 下刷网页的,更像是爬虫,更容易被风控。实测用 Mac 的 UA 会更好。

不要对所有页面都注入脚本

风控页面本身会加载很多的 Iframe 用于跑验证脚本、出验证码之类的,这些东西都会触发页面加载事件。通过 cdp 我们可以直接看到这些页面:

代码语言:javascript
复制
Just a moment...
https://cf-assets.hcaptcha.com/captcha/v1/6fdad99/static/hcaptcha.html#frame=challenge&id=04nubo7q8lgo&host=www.wethrift.com&sentry=true&reportapi=https%3A%2F%2Faccounts.hcaptcha.com&recaptchacompat=off&custom=
false&endpoint=https%3A%2F%2Fcloudflare.hcaptcha.com&hl=zh&assethost=https%3A%2F%2Fcf-assets.hcaptcha.com&imghost=https%3A%2F%2Fcf-imgs.hcaptcha.com&tplinks=on&sitekey=03196e24-ce02-40fc-aa86-4d6130e1c97a&theme=light&origin=https%3A%2F%2Fwww.wethrift.com
https://cf-assets.hcaptcha.com/captcha/v1/6fdad99/static/hcaptcha.html#frame=checkbox&id=04nubo7q8lgo&host=www.wethrift.com&sentry=true&reportapi=https%3A%2F%2Faccounts.hcaptcha.com&recaptchacompat=off&custom=false&endpoint=https%3A%2F%2Fcloudflare.hcaptcha.com&hl=zh&assethost=https%3A%2F%2Fcf-assets.hcaptcha.com&imghost=https%3A%2F%2Fcf-imgs.hcaptcha.com&tplinks=on&sitekey=03196e24-ce02-40fc-aa86-4d6130e1c97a&theme=light&origin=https%3A%2F%2Fwww.wethrift.com
https://cf-assets.hcaptcha.com/captcha/v1/6fdad99/static/hcaptcha.html#frame=challenge&id=12ks6yz7fbwp&host=www.wethrift.com&sentry=true&reportapi=https%3A%2F%2Faccounts.hcaptcha.com&recaptchacompat=off&custom=false&endpoint=https%3A%2F%2Fcloudflare.hcaptcha.com&hl=zh&assethost=https%3A%2F%2Fcf-assets.hcaptcha.com&imghost=https%3A%2F%2Fcf-imgs.hcaptcha.com&tplinks=on&sitekey=03196e24-ce02-40fc-aa86-4d6130e1c97a&theme=light&origin=https%3A%2F%2Fwww.wethrift.com
https://cf-assets.hcaptcha.com/captcha/v1/6fdad99/static/hcaptcha.html#frame=checkbox&id=12ks6yz7fbwp&host=www.wethrift.com&sentry=true&reportapi=https%3A%2F%2Faccounts.hcaptcha.com&recaptchacompat=off&custom=false&endpoint=https%3A%2F%2Fcloudflare.hcaptcha.com&hl=zh&assethos
t=https%3A%2F%2Fcf-assets.hcaptcha.com&imghost=https%3A%2F%2Fcf-imgs.hcaptcha.com&tplinks=on&sitekey=03196e24-ce02-40fc-aa86-4d6130e1c97a&theme=light&origin=https%3A%2F%2Fwww.wethrift.com

在对目标页面加载脚本时,尽量不要对那些校验用的中间页面进行 hook。原先我们有一个对所有加载的页面都打印一下日志的兜底脚本(没有做任何其他事情),本以为没啥影响,结果测试了很久发现,这个兜底脚本的存在极大影响了页面加载的成功率。具体原因未知,但是理论上的确是有办法能够检测到。

尽量提高页面加载速度

Did you know some signs of bot malware on your computer are computer crashes, slow Internet, and a slow computer?

大数据表明,越慢的网络环境越有可能是危险的。各种 Hook 处理、多层代理、抓包解包等都会影响网络响应速度,因此一定要想办法提高。

目前我们采用的抓包代理技术比较老旧,解包太慢了,导致一加抓包代理,页面打开的成功率就骤降。尤其是清除缓存后的浏览器首次打开时,由于缓存被干掉了,资源一起加载就会非常慢。因此我们在已有的抓包代理的基础上又套了一层静态资源缓存,实现对静态资源 Cache-Control 的处理,减少因清除缓存带来的速度变慢的问题。

实测后发现,加了静态资源缓存后,页面打开的成功率也有了明显提升。

改用指纹浏览器

上面的方法虽然基本上能让滑块或者验证码出来,但是仍然解决不了一直验证的问题。测试过很多浏览器之后发现,即使是本地正常的浏览器、正常的IP,很大概率也会出验证的。

但是偶然间发现了一款 GoLogin 指纹浏览器,在不做任何额外配置时、竟然能几乎100%通过 cloudflare 的盾,非常神奇(多次重试均可通过✅);但是在我加了一堆自以为是的配置之后,却又出验证了。看来爬虫浏览器改用指纹浏览器应当是一大趋势。不过目前市面上这类的浏览器基本都是闭源收费的,且价格一般都比较昂贵,只能说多多关注了。。。

有趣的东西

基于V8引擎特性的内核版本判断

通过 JS 校验 V8 引擎在不同 Chromium 内核版本下的特性,可以用来大致判断真实内核状态。如果和 UserAgent 声明的版本不一样,则会是一个非常负面的评价。

根据 V8 的版本说明文档,V8 的版本和 Chromium 版本是一一对应的:

说的很清楚,将 Chromium 的大版本号除以10,即得到了 V8 的大版本号。从 chrome://version 中也可以应证这一点(106.0.5249.103 -> 10.6.194.17):

代码语言:javascript
复制
Google Chrome 106.0.5249.103 (Official Build) (x86_64)
Revision 182570408a1f25ab2731ef5f283b918df9b9f956-refs/branch-heads/5249_91@{#6}
OS macOS Version 12.6 (Build 21G115)
JavaScript V8 10.6.194.17
User Agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36
Command Line /Applications/Google Chrome.app/Contents/MacOS/Google Chrome --flag-switches-begin --flag-switches-end
Executable Path /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

有了这个对应关系,我们就可以通过测试 V8 语言在不同版本下的语言特性,来推断当前 Chromium 内核的版本。我们可以在 V8 的 Features 页查看到 V8 的 Javascript api 各种新特性,选择其中一个希望测试的特性,再去 V8 的 Blog 页查看其对应的版本,从而对 Chromium 内核版本进行甄别。

例如,我们发现 V8 在 9.3 版本新增了一个 Object.hasOwn 方法,那么在 Chromium 内核高于 93 的机器上,下面的 Javascript 就会正常执行:

代码语言:javascript
复制
Object.hasOwn.toString()
'function hasOwn() { [native code] }'

而在内核低于 93 的机器上,下面的 Javascript 就会报错:

代码语言:javascript
复制
Object.hasOwn.toString()
Uncaught TypeError: Cannot read property 'toString' of undefined
at <anonymous>:1:15

通过测试足够多的特征,我们就可以很轻松的精确判断当前浏览器实际的内核版本。

当然,这里直接通过 toString() 来判断函数是否存在的方法比较粗暴,很容易绕过。实际上可以多设计一些测试用例,甚至可以在服务端随机生成测试用例,再将客户端返回的结果与服务端的进行对比,这样即使通过数据抓包、JS 逆向,也挺难处理分析的。

hCaptcha基于指纹和行为打分

和 reCatpcha 类似,hCaptcha 在提供验证服务的同时,也会给后端服务返回当前校验结果的“打分”,用于评判当前的用户时真人或是机器的概率。因此并不是说点对了验过码图片就能100%保证通过风控。

一般来说,这类验证码服务几乎都会通过 JS 收集浏览器的基本信息(尤其是 window.screen 和 window.navigor 下的所有参数),以及用户的行为信息(鼠标的移动序列),传回 hCaptcha 服务端;服务端经过大数据计算后返回类似如下接口的数据给业务后端,用于进行风控判断,这样业务后端就可以根据这个 score 来控制风控强度:

代码语言:javascript
复制
{
"success": true|false,     // is the passcode valid, and does it meet security criteria you specified, e.g. sitekey?
"challenge_ts": timestamp, // timestamp of the challenge (ISO format yyyy-MM-dd'T'HH:mm:ssZZ)
"hostname": string,        // the hostname of the site where the challenge was solved
"credit": true|false,      // optional: whether the response will be credited
"error-codes": [...]       // optional: any error codes
"score": float,            // ENTERPRISE feature: a score denoting malicious activity.
"score_reason": [...]      // ENTERPRISE feature: reason(s) for score.
}

本来我也想测试下自己的定制浏览器的实际得分,奈何这个 score 只对企业级用户开放,普通开发者是拿不到的。

寻找了一圈倒是发现 reCaptcha 有类似的 demo ,不过仔细一看,他返回的 score 也只是个 demo ,不具参考意义。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 环境
  • 解决
    • 关闭 --single-process 配置
      • 关闭--disable-site-isolation-trials 配置
        • Chromium 内核版本尽量用较新的版本
          • 不要对所有页面都注入脚本
            • 尽量提高页面加载速度
              • 改用指纹浏览器
              • 有趣的东西
                • 基于V8引擎特性的内核版本判断
                  • hCaptcha基于指纹和行为打分
                  相关产品与服务
                  验证码
                  腾讯云新一代行为验证码(Captcha),基于十道安全栅栏, 为网页、App、小程序开发者打造立体、全面的人机验证。最大程度保护注册登录、活动秒杀、点赞发帖、数据保护等各大场景下业务安全的同时,提供更精细化的用户体验。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档