使用hashids库混淆在url中与数据库相关的数字


#算法#


2014-05-31

很多情况下,在url中过于明显的显示数据库中的一些信息并不是什么良好的实践。比如,在数据库中某个movie表:

CREATE TABLE movie(
id int primary key not null auto_increment,
path text
)

如果要以网页的形式播放这些视频,url格式可能如下:

http://www.example.com/play/{id}

例如要播放id为1的视频:

http://www.example.com/play/1

这种url很有规律性。对此,如果要有一个恶意的信息抓取程序住去依次页面信息:

http://www.example.com/play/1
http://www.example.com/play/2
http://www.example.com/play/3
http://www.example.com/play/4
...

example.com网站的拥有者一般不乐意这种情况发生。要避免这种情况,使用对称加密的方式处理这些id是一个很好的解决方案。

hashids是一个很好的选择,其提供了js、ruby、python、java、php、perl、coffeescript、objective-C、Go、Lua、Node.js等编程语言的实现,具体请移步官网hashids

使用hashids,可以将1转换为4q2VolejRejNmGQB(当然,也能转换成其他的字符串,详见下文),也可以将4q2VolejRejNmGQB逆转为1

下面是python版本教程的简单翻译,原文见hashids-python

安装

pip install hashids

如何使用

如何导入

from hashids import Hashids
hashids = Hashids()

基本使用

加密单个整数:

hashid = hashids.encrypt(123) # 'Mj3'

解密一个哈希值(加密后的值):

ints = hashids.decrypt('Mj3') # (123,)

加密多个整数:

hashid = hashids.encrypt(123, 456, 789) # 'El3fkRIo3'

解密多个整数:

ints = hashids.decrypt('1B8UvJfXm') # (517, 729, 185)

使用自定义的盐值(salt)

例子1:

hashids = Hashids(salt='this is my salt 1')
hashid = hashids.encrypt(123) # 'nVB'

例子2:

hashids = Hashids(salt='this is my salt 2')
hashid = hashids.encrypt(123) # 'ojK'

盐值字串的长度最好在6到32之间。

控制加密后字串的长度

加密:

hashids = Hashids(min_length=16)
hashid = hashids.encrypt(1) # '4q2VolejRejNmGQB'

解密:

hashids = Hashids(min_length=16)
hashids.decrypt('4q2VolejRejNmGQB') # (1,)

使用自定义的字母表

加密得到的字符串中的所有字符都来自字母表,默认的字母表是:

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890

字母表是可以自定义的,例如全部是小写字母:

hashids = Hashids(alphabet='abcdefghijklmnopqrstuvwxyz')
hashid = hashids.encrypt(123456789) # 'kekmyzyk'

自定义的字母表中的字符至少应含有16个字符。

随机性

hashids的主要目标是混淆id,这并不意味着它适合用来加密或者压缩。虽然是对称加密,不过其“随机性”还是很好的。

例如加密重复的数字:

hashids = Hashids("this is my salt")
hashids.encrypt(5, 5, 5, 5) # '1Wc8cwcE'

加密递增的数字:

hashids.encrypt(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) # 'kRHnurhptKcjIDTWC3sx'

hashids.encrypt(1) # 'NV'
hashids.encrypt(2) # '6m'
hashids.encrypt(3) # 'yD'
hashids.encrypt(4) # '2l'
hashids.encrypt(5) # 'rD'

会不会生成的字串里有脏话?

hashids的算法尝试避免生成常见的英文脏话,方法是不让下面的这些字符相邻:

c, C, s, S, f, F, h, H, u, U, i, I, t, T

( 本文完 )