反爬之ID 混淆 hashids 了解下

By 刘志军 , 2020-05-07, 分类: python

hashid

爬虫与反爬是一对相生相克的死对头,道高一丈魔高一尺。作为爬虫的一方,如果知道了某个站点的数据自增ID,那么就能轻而易举把整个站点都爬下来。是不是有点耸人听闻,你去看很多大站例如油管、P站等,他们都不会轻易把业务的自增ID暴露出来,而是用一种可逆的hash字符串替代。

微信截图_20200422204432.png

最常用的ID混淆就是Hashids。Hashids是一个小型的开放源代码库,可以将数字生成很短的、唯一的、非顺序的字符ID。

例如可以数字347转换为 “yr8” 字符串,你还可以将字符串ID进行解码恢复成数字。

微信截图_20200422193518.png

下面就来看看咋使用的

安装

pip install hashids

怎么使用

首选初始化一个 hashids 实例

from hashids import Hashids
hashids = Hashids()

编码(加密)

>>> id = hashids.encode(1)
>>> id
'jR'
>>> hashids.encode(123)
'Mj3'
>>> hashids.encode(1234)
'1lj'
>>> hashids.encode(12345)
'j0gW'
>>> hashids.encode(123454)
'v27AV'

生成的字符ID长度与和数值大小有关。

解码(解密)

>>> num = hashids.decode('jR')
>>> num
(1,)
>>> hashids.decode("Mj3")
(123,)
>>> hashids.decode("1lj")
(1234,)
>>> hashids.decode("j0gW")
(12345,)
>>> hashids.decode("v27AV")
(123454,)

解码后返回时一个元组。

如果你解码一个随机的字符串ID,不一定能恢复成数字,此时会返回空元组。

>>> hashids.decode("werwer")
()

因为hashid可逆,所以别人拿到字符串后也能根据字符串ID反推出数字,因此,为了避免别人猜出原始数字ID,我们在编码的时候可以指定盐值。理论上,只要盐值不被泄露,被破解的难度就加大了很多。

指定盐值

初始化 hashids时候,可以指定盐值

>>> hashids = Hashids(salt="XXXX")
>>> hashids.encode(123)
'1LY'
>>> hashids.decode("1LY")
(123,)

同样的数字使用不同的盐值编码得到的字符串是不同的,别人就无法猜出原始ID是多少了。

限制hash长度

默认情况下,数字越小,编码生成的字符串也比较短,为了将不同大小的数值转换为统一长度的字符串,在初始化hashids的时候,可以指定hash的最小长度

>>> hashids = Hashids(salt="XXXX", min_length=10)
>>> hashids.encode(123)
'PyNd1LYK3G'

限制hash的字符种类

如果你不希望hash中有大写字母,那么可以在初始化的时候,指定hash字符串的范围,例如我们可以指定为所有的小写字母

>>> hashids = Hashids(alphabet="abcdefghigklmopkrst")
>>> hashids.encode(123)
'ggdo'

需要注意的时候,alphabet至少要指定16个以上的不同字符。

hashid 简单却实用,是避免业务ID外露办法之一。

今日思考题

你知道hashids的实现原理是什么吗? 留言区第一个答对的奖励1本算法书。


关注公众号「Python之禅」,回复「1024」免费获取Python资源

python之禅