地震高岗,一派溪山千古秀;
门朝大海,三河合水万年流;
没错,这正是《鹿鼎记》天地会的接头暗号。
天地会为什么需要接头暗号呢?
假设天地会赤火堂香主派人从京城前扬州将一封非常重要的密函交给青木堂香主韦小宝,我们可以将这件事抽象为下图:
这件事的核心是帮派成员-甲将重要密函交给帮派成员-乙。假设甲、乙双方互不相识亦从未有过会面,那帮派成员-甲如何排判断密函交给了帮派成员-乙,而不是给错人——给了其他帮派成员-丁呢?
在历史实践中肯定吃过这样的亏,遂天地会采用了接头暗号这种方式来确保甲、乙双方是同一帮派成员,这才有了:
地震高岗,一派溪山千古秀;
门朝大海,三河合水万年流;
暗号只有帮派成员才知道,且不可外泄。甲、乙双方见面时由帮派成员-甲说出地震高岗,一派溪山千古秀,帮派成员-乙听到后必须接下一句门朝大海,三河合水万年流。如果帮派成员-乙不知道下一句是什么,或者胡说一气,那么帮派成员-甲就可以判定他不是接头人,而是冒充的。
同样的,帮派成员-乙要听到帮派成员-甲说出地震高岗,一派溪山千古秀。否则帮派成员-甲就是冒充的,很有可能会将假的密函交给青木堂韦小宝。
天地会接头人互相传递消息(密函)很像是我们在开发 WEB 应用时的 Client 和 Server,抽象地看起来像这样:
那么问题来了,Client 和 Server 之间需不需要天地会这样的暗号呢?
答案是需要!
Client 就像帮派成员-甲,Server 就像帮派成员-乙,而他们的密函很有可能会被其他帮派成员-丁拿走或伪造。既然天地会有接头暗号,那么 Client 和 Server 之间用什么来保障传递消息是第一手发出,而不是被拦截伪造的呢?
没错,签名验证!
签名验证是目前 IT 技术领域应用广泛的 API 接口数据保护方式之一,它能够有效防止消息接收端将被篡改或伪造的消息当作正常消息处理。
⚠️要注意的是,它的作用防止消息接收端将被篡改或伪造的消息当作正常消息处理,而不是防止消息接受端接收假消息,事实上接口在收到消息的那一刻无法判断消息的真假。这一点非常重要,千万不要混淆了。
假设 Client 要将下个月 5 号刺杀鳌拜这封重要密函交给 Server,抽象图如下:
这时候如果发生冒充事件,会带来什么影响:
其他帮派成员-丁从 Client 那里获得消息后进行了伪造,将刺杀鳌拜的时间从 5 号改为 6号,导致 Server 收到的刺杀时间是 6 号。这么一来,里应外合刺杀鳌拜的事就会变成一方延迟动手,这次谋划已久的刺杀行动大概率会失败,而且会造成不小的损失。
我们使用签名验证来改善这个消息传递和验证的事,这里可以简单将签名验证理解为在原消息的基础上进行一定规则的运算和加密,最终将加密结果放到消息中一并发送,消息接收者拿到消息后按照相同的规则进行运算和加密,将自己运算得到的加密值和传递过来的加密值进行比对,如果两值相同则代表消息没有被拦截伪造,反之可以判定消息被拦截伪造。
这里我们通过实际网站中的例子来加深理解,打开 http://www.porters.vip/verify... ,网页如下图所示:
鼠标点击图片中黄色的按钮——点击查看详情,此时网页内容产生变化,页面如下图所示:
为了观察和分析,我们唤起浏览器内置的开发者工具(快捷键 F12 或 Command+Option+I)并切换到 Network 面板。此时刷新页面,并再一次点击黄色按钮。点击后我们会在 Network 面板中看到很多网络请求记录,其中有一条 Name 很长的请求,点击它。
点击它后 Network 面板将会分为左右两栏,左侧依旧是请求记录,右侧是我们选中的请求记录的请求详情。我们选中的这条网络请求信息如下图所示:
从 General 和 Query String Parameters 中我们得知本次向 http://www.porters.vip/verify... 接口发出的请求中携带了 actions、tim、randstr 和 sign 等 4 个参数。这里的 sign 字段和对应的值就是签名验证中的签名,即经过一定规则运算和加密的值。
如果没有 sign,Client 只将 actions、tim 和 randstr 发送给 Server,那么帮派成员-丁可以很轻松地伪造一条消息发送给 Server,例如:
Server 收到后就当作正常的消息处理,根本无从判断消息是谁发的,有没有被拦截、篡改。那么问题来了:sign 在这里发挥了什么作用呢?
假设 sign 的运算规则为:
sign = MD5(str(actions + 10086) + str(tim) + randstr * 3)
Client 中设定的这个运算规则相当于接头暗号中的上半句地震高岗,一派溪山千古秀,而 Server 端拿到 actions、tim、randstr 和 sign 之后,用相同的运算规则计算 new_sign 的值,最后判断 Client 发送的 sign 和 Server 自己计算的 new_sign 是否一致,看起来像这样:
new_sign = MD5(str(actions + 10086) + str(tim) + randstr * 3)
当然,这里的交互只是单向的,Server 端不必将门朝大海,三河合水万年流回复给 Client(其实可以这么做,但在网络通信中没有必要)。就算其他帮派成员-丁拦截到消息,并进行了篡改也不会对 Server 造成影响,因为其他帮派成员-丁并不知道 sign 是如何运算的,他篡改后的的数据计算出的 new_sign 和收到的 sign 是不同的,因此 Server 能够区分真假消息并丢弃假消息。
有了接头暗号后,消息接收方 Server 就不用担心拿到的是假密函了。
签名验证被广泛应用,例如下载操作系统镜像文件时官方网站会提供文件的 MD5 值、阿里巴巴/腾讯/华为等企业对外开放的接口中鉴权部分的 sign 值等。
本文改编自《Python3 反爬虫原理与绕过实战》第 4 章第 3 小节,这本书是爬虫领域第一本专门介绍反爬虫的书,从“攻”与“防”两个角度描述了爬虫技术与反爬虫技术的对抗过程,并详细介绍了这其中的原理和具体实现方法。通过这本书,你将了解到签名验证、文本混淆、动态渲染、加密解密、代码混淆和行为验证码等反爬虫技术的成因和绕过方法。书本中介绍到的反爬虫知识覆盖了市面上 90% 以上的反爬虫手段知识点,非常硬核。
掌握这些知识后,你的理论基础将非常扎实,能够轻松应对一线大厂中高级爬虫工程师面试的理论和思路问题。实战方面,除了本书搭建的21个在线练习示例之外,还需要结合工作中遇到的综合反爬虫进行演练,从而稳步提升个人技术实力。
⏰ 本文使用的示例网站 http://www.porters.vip/verify... 正是书中 21 个在线练习示例其中的一个。
本书在预售阶段销量就超过了1000本,第一批出版后被广大工程师一抢而空,立即申报了第二批印制,由此可见火爆程度。
本书参与了京东图书 5 折活动,现价只需要44.5元,快去抢购吧!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。