小程序base64 图片for循环多个展示不了_向武大图书馆预约系统背后的程序员:致敬、致歉...

本文讲述了作者在遇到图书馆预约系统采用滑块验证后,如何通过分析JavaScript代码和利用Python进行图像处理,尝试破解这一验证机制的过程。在解析混淆加密的JS文件、理解图片碎片重组算法后,最终成功定位滑块验证的偏移量。文章揭示了验证码技术与自动化工具之间的博弈,同时也展示了技术在维护公平性方面的应用。
此文章时效性已过期。

又是美好的一天。我习惯性地打开「WHUers」预约自习座位,一个猝不及防的提示却让我差点再睡过去——“登录失败,系统异常,请稍后重试。”这一瞬间我的心里只有三种想法:

  1. 学校的图书馆系统崩了;
  2. 阿里云宕机了;
  3. 世界末日了。

我绝不相信自己昨晚新写的代码又出了问题,这是作为开发者该有的骨气。

于是我尝试打开图书馆网站——

f8b158a06c340c15187f7392b87c068b.png
新上线的滑块验证

原来在抢座脚本肆无忌惮的猖獗之下,图书馆预约系统上线了滑块验证。

这让我想起彼时为了优雅地解决验证码的问题,标识了大量的图片验证码样本,以供机器学习训练。没想到一夜之间,曾经眼睛胀痛、手指麻木换来的成果都付之东流。

8fcd1026a16191782ef136937cf1f0ca.png
为机器学习而标识的验证码

我甚至可以想象,这背后的程序员在寒冷的冬夜里是怎样点着蜡烛(也许他们并不断电)、喝着咖啡,绞尽脑汁去向投机取巧的脚本家们反击——只为了给普通同学提供公平的自习机会。也许他手腕会酸,也许他颈椎会疼,甚至连脱落的银丝都给了他寒舍飘雪的幻象——思绪至此,不禁热泪盈眶。收拾一下心情,按下 F12。


在点击“请点此进行验证”按钮时,监测到浏览器发起了一个名为 verifyCode 的请求,它为我们返回了一个 HTML 页面。我们将其在新的页面打开——

26dda06a566e3e5f4cd271ac7412ede4.png

一目了然,这是一个纯粹的滑块验证页面,它被嵌套在了原来的登录页面里。

查看这个页面的源代码,可以找到几个有用的 JavaScript 脚本文件:verify-code.js、dragdealer.js、bigdecimal.min.js。经验使然,提取出最重要的 verify-code.js,另外两个分别是 jQuery 的滑块组件和 JS 的高精度计算库。

与此同时,监测到在加载此验证页面时浏览器发起了一个名为 verifycode(这次是小写 c)的请求。它为我们返回了一些 JSON 数据——

91581a6fea2ab9cb0a2825615e14b00b.png

顾名思义,在 data 键值里它告诉了我们完整的图片数据(wholeImg)、缺少的图片块(repairImg)、图片块的大小(repairWidth/Height)、身份标识码(verifyCode)以及目前不知道什么用的 point 值。

回到验证页面里,我们去体验一下这个滑块。

当拖动滑块完成验证时,浏览器又发起了一个请求,名为 verify——

8c117f6952027daee91ca01b7db0f83c.png

这次,它向服务器转达了一些信息。一共有四个字段。显然,xvalue 为滑块向右滑动的水平偏移量,yvalue 和 appId 在多次请求中始终为固定值。而 code 的值又与刚刚的身份标识码(verifyCode)一样。

再看看它给我们返回了什么信息——

fa3446a5d30bff122e4b03f48f198561.png

仍然是一些 JSON 格式的数据。在 data 键值里它告诉了我们当前的 IP 地址(ip)、完成滑块验证的用时(authStart/StopTime)以及最重要的认证标识码(authId)。

这意味着,服务器认为当前访问的用户已经完成了滑块验证,你可以畅通无阻地输入学号和密码登录进系统了。

事情至此似乎一切都变得简单起来:只要我们找出滑块所需的向右的水平偏移量 x,就可以伪造请求告诉服务器当前用户完成了滑块验证。可是问题来了,怎么去计算出需要的水平偏移量呢?

我想起了开头提到的那个最重要的 JS 脚本文件 verify-code.js,让我们去一探究竟。

打开这个 JS 文件,并不大,只有 8KB,然而——

b3472a9672ab3c822ae54f907b14ae88.png
这似乎不是印象里 js 文件该有的样子

它被混淆并加密了。

我们有一些盲目乐观了。挠一挠头发,我们尝试去解除混淆并人工解密。

第一步,先将 UTF-8 编码的字符解码,得到一个包含有多个字符串的字符串数组,里面包含一些常见的 js 指令。

第二步,将字符串数组的索引值由十六进制转换为十进制,并替换原字符串,得到其中一个较为清晰的函数——

function 

这是发起名为 verifycode 请求的命令,我们前文已经解析过了。

第三步,通过字符串替换等等,对剩下的代码进行分析。只可意会,难以言传,幸在代码并不长。我来把解出的代码进行重点分析(所有的变量名均为自定义的)。

var 

这两句是用之前名为 verifycode 的请求获取到的完整的图片数据(wholeImg)构建一个 Image 对象。

我们不妨去看一看这个完整的图片到底是什么样的。直接将 Base64 编码的图片数据放在浏览器的地址栏,按下回车。

4869185ee6ef5b865101f32841d9d869.png
我不知道该说什么

……

我想这当中可能有些许误会。为什么我们获取到的图片是一张“马赛克”,而浏览器里显示的却是一张完好的图片?这其中必定有某种未知的转换方式。

耐着性子继续往下分析。

var 

这段代码很神奇。通过最后一句我发现,只有经过这番处理之后,完整的图片才被显示出来。而上面的一系列循环操作又是什么意思呢?

我们找回通过 verifycode 请求获取的到的当时不知什么用的 point 数据。

{
    

经过 JSON 解析,point 数据的 point 键值是一个对象数组,每一个对象都有 x 和 y 两个坐标元素。

答案似乎将要浮出水面了。

原本完整的图片被分成了 30*15 个碎片,这些碎片被打乱排布以使得我们看到了一张“马赛克”。而 point 数组里共有 450 个坐标元素,这些坐标数据正是这些碎片的正确排列方式。我们可以按照代码里既有的算法,将这些碎片重新排列。

下面我们开始写代码。人生苦短,我用 Python。

运行环境 Windows 10,Python 版本 3.6.6,用到的库:PIL、BytesIO、OpenCV、AirCV、Requests、Base64、JSON。

国际惯例,先构造请求头。模拟之前名为 verifycode 的请求,获取返回的 JSON 数据并解析。将 Base64 编码的完整图片数据解码并保存。

url 

接下来,按照 point 数组里的坐标数据,对原图片进行切割和拼凑,生成新图片并保存。

img 

得到结果。

6b5a6d61d5a8b6bbe0a07287d18acdb2.png
用 Python 将碎片重新排列后得到的图片以及原图片

我们要找什么来着?滑块的偏移量 x。

我们先截取出图片中的补偿部分,保存为“tile.jpg”。

558d6b39e34270383c5ad49810dfc068.png

最后,利用 AirCV 库提供的 find_template 方法,找出这一小块在原图中的位置。

father 

运行一下,大功告成。

5c7f20daddbf3c3a3cbc618dd55782eb.png
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值