用 Hashids 把数据库 ID 藏起来
最近在做一个对外 API,设计的时候有个问题挺头疼的——数据库用自增 ID,但直接把 /users/1、/users/2 这种 URL 暴露出去总感觉不太好。用户一看就知道你有多少用户,还能遍历爬数据。
一开始想过用 UUID,但那玩意儿太长了,36 个字符,URL 看着巨丑。后来无意中刷到一个叫 Hashids 的库,专门干这事的。
这玩意儿是干嘛的
简单说就是把数字 ID 转成类似 YouTube 视频链接那种短字符串。
比如 jN5、k8xQ 这种,看着就像随机生成的,但实际上可以还原回原来的数字。这样用户看到的 URL 就是 /users/jN5,根本猜不出来有多少用户,比自增 ID 隐蔽多了。
安装一把梭
Composer 安装就完事了:
1 | composer require hashids/hashids |
注意需要装 bcmath 或 gmp 扩展,不然会报错。
基本用法
用起来贼简单:
1 | use Hashids\Hashids; |
有个小细节要注意,decode() 返回的永远是数组,即使你只编码了一个数字。所以取值要这样写:
1 | $id = $hashids->decode($hash)[0] ?? null; |
几个配置参数
构造函数可以传三个参数:
1 | $hashids = new Hashids( |
盐值很重要,不同项目的盐值不一样,生成的哈希就不一样,可以防止被破解。
最小长度这个参数也挺有用,比如你想要所有 ID 都至少 8 位,短的会自动填充,看着更统一。
一个小坑
刚开始用的时候发现,传无效的哈希字符串去解码,不会报错,而是返回空数组。所以要判断解码是否成功:
1 | $decoded = $hashids->decode($hash); |
还有不支持负数,传负数进去会返回空字符串,这点文档里有写但容易忘。
不是加密,不是加密,不是加密
重要的事情说三遍。Hashids 的作者在文档里反复强调,这不是加密库,不要用来加密敏感数据。
它能做到的只是”混淆”,让数字看起来不像数字。真要保护数据还是得靠权限控制和加密传输。我理解它更像是”给 ID 穿了件马甲”,防君子不防小人。
顺便提一句
原作者后来又出了个新版本叫 Sqids,本质上是一样的东西,据说算法有些改进。新项目可以考虑用 Sqids,不过 Hashids 也在维护,用着没啥问题。
最后
这个库在我们项目里用了大半年,效果挺好的。API 的 URL 看着干净,也避免了一些简单的遍历攻击。唯一的缺点就是调试的时候要看数据库记录得先解码一下,不过写个小脚本就能搞定的事,不算什么大问题。
如果你也在为暴露自增 ID 这事头疼,可以试试 Hashids,轻量好用,一个 Composer 包就搞定。