Hashids 是一个非常小巧的跨语言的开源库, 它用来把数字编码成一个随机字符串. 它不同于 md5 这种算法这种单向映射, Hashids 除了编码还会解码.
拿论坛来说, 一般帖子在数据库里的 id 都是顺序递增的, 但是你可能不想在 url 上直接把 id 暴露出来, 以免爬虫直接遍历 id 爬取你的内容, 给你带来损失. 那现在你就可以使用 Hashids 把这个 id 搞乱, 让它失去顺序性, 无法直接遍历, 这样就可以直接提高了爬虫的门槛. 著名的 Youtube 网站就是这么做的.
我们来看看它怎么使用 首先安装一下
pip install hashids
我们看到 hashids 不仅可以编码一个整数, 还可以一次编码多个整数. 解码的时候不需要对字符串进行分割, 可以直接解码成多个整数. 这在存储一个帖子的相关帖子时给我们多了一种选择, 一般我们使用 json 打包多个帖子 id 放在帖子表的一个字段里, 现在我们就可以使用 hashids 把它们编码成一个字符串塞进去了, 可以节省一定的存储空间. 不过, 除此之外我想不到编码多个整数有什么其它的用途了.
hashids 需要提供一个 salt 值, 相当于编解码的私钥, 别人不知道你的私钥, 就无法编码出对应的帖子的展现 key, 也无法通过 url 上的展现 key 解码出对应的帖子 id. 所以想直接遍历你的帖子服务那就做不到了.
现在我们试试随便提供字符串, 对它进行解码会怎样
我们看到这些字符串都是非法, 所以 hashids 无法解码出对应的整数.
下面我们对一段连续整数进行编码
可以发现编码之后的值在直觉上是没有任何规律可言的.
鉴于 hashids 是如此的小巧, 笔者随后对它的源代码进行了一番研究. 首先看看它的构造器
我们发现可以设置编码后字符串的最小长度. 如果你不设置这个最小长度, 对于一个从 0 开始的自增 id, 编码出来的字符串长度一开始只有 2 位, 但是随着 id 的增长, 编码后的长度也越来越大, 但是最终这个长度值越来越稳定, 因为位数越大可以表达的数值就越多. 如果我们设置了这个最小长度, 在 id 没有恐怖的快速增长的情况下, 那么编码出的长度一开始就是非常稳定的.
然后我们还可以设置映射字典. 默认是 base64[26+26+10] 编码, 如果你不喜欢大小写敏感, 可以改成 base36[26+10] 编码, 甚至可以改成火星文, 如果你真这么无聊的话.
注意火星文的字典必须是 unicode 类型. 不然你编码得到的不是火星文, 而是乱码. 具体实现算法我就跳过了, 有点复杂, 我就不讲了.
然后它还支持对 16 进制字符串进行编解码, 看来 mongodb 的 id 也可以纳入进来了.
最后算法的实现原理, 仔细研究了一下, 有点复杂, 很难三言两语讲清楚, 有兴趣的话读者还是自己阅读官方文章吧. 算法的作者不保证安全性, 不建议将 hashids 用在安全领域.
维基百科提到一个理想的 hash 算法需要满足下面 3 个特性
正向计算 hash 很容易
反向破解 hash 极其困难
hash 值碰撞概率极小
hashids 满足第 1 和第 3 条, 正向计算 hash 很快, hash 值完全没有碰撞, 保证了唯一性. 如果知道 salt 值, 还可以逆向通过 hash 值计算出原值. 那第 2 条是否满足取决于你的 salt 秘钥有多容易被攻击者拿到. 如果你的 salt 秘钥来自于常用字典单词, 那攻击者可以通过彩虹字典快速将秘钥破解. 你把秘钥好好保护, 设置的随机一点长度长一些, 安全性还是可以得到保障的.
最后你可千万别把秘钥搞丢了, 一旦搞丢了, 就意味着所有帖子的展现 id 需要重新计算一边, 变的跟以前不一样了, 搜索引擎收录的所有网页就失效了, 别人外链过来的地址全都打不开, 这无疑会给你的网站带来很大的损失.
来源: https://juejin.im/post/5ac9e913f265da237d0348ae