爬虫不只是单纯地获取信息,也会进行一些自动提交信息的操作。识别 Form 表单提交行为是人或机器有许多方式,最近后端同事提出一种方式:
记录用户提交表单前鼠标操作的轨迹,如果每次都一样(或没有),则可以判断是非人为操作。

结合 rrweb(Record and replay the web) 提供的一些能力,我们尝试做了一种方案。

大致的思路就是,当用户开始对表单进行一系列操作的时候,开始记录鼠标的事件(主要就是移动和点击这两个事件)。当收集到足够信息后返回给服务端进行对比(选择通过Cookie的方式和表单信息一起提交至后端),如果每次表单操作的相似度超过一定预设值(80%)则认为这不是正常的人为操作。

唯一的问题就是 Cookie 的值要怎么设定。

最后决定取鼠标开始操作后的 16个经过的点 + 16个点击的点 共32个点 的位置(x,y的值)来记录。

rrweb 记录的数据

但如果把这些数据全塞进Cookie传给服务端有点太多了,直接hash的话只要有一点不一样就会完全不同,没有相似度一说。于是我们决定取每个点的 x + y 组合成字符串后取 md5 的第10位,每个点对应一个字符。

1
MD5(`pos_${pos.x}_${pos.y}`).toString()[0]

但有个问题是鼠标基本没怎么操作,不够32个点。于是决定不满的点补0。一旦 0 表示的是空缺,那 md5 取到的正好是 0 的情况就需要跳过。一种是往后取一位直到取不到 0,或者直接不用这个点。

1
.map(str => str.padEnd(16, '0')) // 不足16位补0
红色为移动,蓝色为点击,不足补零

有些极端情况,没有鼠标和触摸板,只用 tab 去操作页面,这时候32位全是0,这种情况暂不考虑;
还有个情况是用户迟迟不提交,会记录冗余的点数,所以当获取到200个鼠标事件的时候,就停止记录。

由于每个点都单独取 md5,并且验证的是相似程度,所以不用担心取的时间有差异,只要经过了一系列的点,都会记录对应字符。

准备好后接下去只要将它命名,设置成会话Cookie,在表单提交的时候一并交给后端。