V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
kkk212
V2EX  ›  程序员

根据 id 生成唯一可反转短字符串(防止用户 id 等暴露), 用 hashids 稳妥不?

  •  
  •   kkk212 · 2018-12-19 11:55:56 +08:00 · 6027 次点击
    这是一个创建于 2170 天前的主题,其中的信息可能已经有所发展或是发生改变。

    https://hashids.org/ Hashids is a small open-source library that generates short, unique, non-sequential ids from numbers.

    It converts numbers like 347 into strings like “ yr8 ”, or array of numbers like [27, 986] into “ 3kTMd ”.

    You can also decode those ids back. This is useful in bundling several parameters into one or simply using them as short UIDs.

    比如字符串长度设置 4-6 位,等用户量大了接近 4-6 位字符能表示的用户量时, 会不会出现重复的。

    39 条回复    2018-12-20 02:04:55 +08:00
    luosuosile
        1
    luosuosile  
       2018-12-19 11:58:41 +08:00   ❤️ 1
    我也遇到这个问题了,,帮顶吧。。本来我都打算用 uuid 了,顺带一提网上搜到的 short uuid 不太靠谱,评论都说几万条就重复了。
    kkk212
        2
    kkk212  
    OP
       2018-12-19 12:07:37 +08:00
    @luosuosile 我目前用的方案是,单独建一个表添加唯一索引,随机生成 6 位的字符串,然后插入千万条记录。这样是能保证重复问题,但是用的时候增加了一条 sql 查询。hashids 优点是能直接加密反转,不过还不太敢用。
    binux
        3
    binux  
       2018-12-19 12:13:36 +08:00
    Do you have a question or comment that involves "security" and "hashids" in the same sentence? Don't use Hashids. Here are some ways to decode:

    https://hashids.org/#decoding

    前面有个帖子我就说了,找个加密算法(比如 AES )算一下就行了。
    kkk212
        4
    kkk212  
    OP
       2018-12-19 12:23:15 +08:00
    @binux 怎么做到短字符串呢,比如 id 30 用 3jdhey 代替
    jedrek
        5
    jedrek  
       2018-12-19 12:31:48 +08:00
    hashids 不是用来加密的, 这东西和 base64 是一样的东西, 区别是 hashids 可以加个盐再编码
    binux
        6
    binux  
       2018-12-19 12:33:39 +08:00
    @kkk212 用 ctr 模式
    binux
        7
    binux  
       2018-12-19 12:42:06 +08:00
    @binux 看了下 ctr 模式可以算出加密用的块 stream 啊,你用小一点的块?
    kkk212
        8
    kkk212  
    OP
       2018-12-19 12:55:23 +08:00
    @binux 主要看到一些网站,用户主页的 id 有用用户昵称的,有用字符串的( 6 位左右)。用字符串的话,比如用 MD5 就行,但是 16 位或 32 位太长了不好看。开始没看 hashids 原理, 感觉 hashids 可以,有点缺点就是不定长和能看出来原数字的大小。谢谢,我一会再看看 aes
    kkk212
        9
    kkk212  
    OP
       2018-12-19 13:11:37 +08:00
    嗯,看了 hashids 原理明白了。但是为什么说不是用来加密的,加了盐值就和 base64 只是编码转换不一样了
    kkk212
        10
    kkk212  
    OP
       2018-12-19 13:12:42 +08:00
    @jedrek 嗯,看了 hashids 原理明白了。但是为什么说不是用来加密的,加了盐值就和 base64 只是编码转换不一样了
    xenme
        11
    xenme  
       2018-12-19 13:22:41 +08:00 via iPhone
    看你要求多安全,一般安全性自己撸一个 base64 的变种,基本没人看得出来,也是最简单的加密。不要说 base64 不是加密,只是大家都知道加解密方式而已。
    leonard916
        12
    leonard916  
       2018-12-19 13:25:02 +08:00
    @xenme 確實不是加密 只是把 byte[]變成字符串而已
    xenme
        13
    xenme  
       2018-12-19 13:33:26 +08:00
    有哪种加密不是把 byte[]或者 string[]变成另外一串 byte[]或者 string[]么?
    只是变换的方式(加密算法)不同罢了。

    只是说现在 base64 类型的加密实在没有安全性,而且更多被人用来当做一种编码方式而已。
    jedrek
        14
    jedrek  
       2018-12-19 13:51:33 +08:00
    @kkk212 加了盐值是跟默认编码后结果不一样, 有了个“定制化”的编码结果. 但是编码算法是一样的.
    并不是说 hashids 完全不行, 还是取决你的用途, 如果想把一长串数字缩得很短, 直观上看不出来, hashids 是个很好的方案; 但若为了不让客户端知道解码后的值, 就不应该这么做, 因为很容易就能破解, 应该考虑对称加密的算法.
    jedrek
        15
    jedrek  
       2018-12-19 13:54:46 +08:00
    @kkk212 加了盐值是跟默认编码后结果不一样, 有了个“定制化”的编码结果. 但是编码算法是一样的.
    并不是说 hashids 完全不行, 还是取决你的用途, 如果想把一长串数字缩得很短, 直观上看不出来, hashids 是个很好的方案; 但若为了不让客户端知道解码前(此处修正)的值, 就不应该这么做, 因为很容易就能破解, 应该考虑对称加密的算法.
    woodensail
        16
    woodensail  
       2018-12-19 13:58:02 +08:00
    @xenme 现代密码学中,安全性不来自于算法的保密而来自于密钥的保密。所以 base64 和各种不引入外部密钥的数据编码方案都不能称之为加密。
    xenme
        17
    xenme  
       2018-12-19 14:14:45 +08:00
    @woodensail 针对楼主的需求来说,算法和密钥都是不需要公开的,安全性要求不是特别高的情况下,类似 base64/hashid 这种“加密”足够满足需求了。
    kkk212
        18
    kkk212  
    OP
       2018-12-19 14:27:39 +08:00
    @xenme 可 hashid 的算法是暴露的
    woodensail
        19
    woodensail  
       2018-12-19 14:29:31 +08:00
    @xenme 同楼上,不要把希望寄托在别人不会拆包上,搞黑产的有这个耐心。
    jedrek
        20
    jedrek  
       2018-12-19 14:29:46 +08:00
    @kkk212 这么说可能都脱离了你的用途了. 说说你的用途和为啥想这么用. 说不定有更好的方案
    xenme
        21
    xenme  
       2018-12-19 14:30:54 +08:00
    个人以为加盐后,hashid 足够满足你要求了。
    默认 hashid 基本是 base62,6 位的话,最多可以表示 56800235584,超过 500 亿,你用户量也不可能更多了。
    xenme
        22
    xenme  
       2018-12-19 14:39:58 +08:00
    @woodensail 前面也说了,安全性要求并不是特别高的话,可以考虑 hashid,毕竟即使黑进后台了,也就知道个用户量而已或者用户真正的 ID,并不能怎么样。而且,即使用更安全的算法,能进来看到算法和 salt 的人,估计你的安全算法的密钥也暴露了。
    @kkk212 这个 id 的 hash 应该是你在用户注册之后,在后台生成后返回给前台用来代替 user id 的。所以,对应的算法以及 salt 是只有后台人员才知道的。你并不需要在前台编解码,所以并没有暴露出来。
    kkk212
        23
    kkk212  
    OP
       2018-12-19 14:40:28 +08:00
    @jedrek 就是用一个短的字符串代替用户 id 来显示, 不能解密也不会暴露真实的 id。目前用的方案是,生成好一个存储 6 位字符串记录的表(插入 2000 万记录), 创建新用户的时候查出来对应 id 的字符串,存到用户表里。但是用户多了,存储字符串的表查询就会慢了,并且这样得定期维护字符串表,感觉费事。
    jedrek
        24
    jedrek  
       2018-12-19 14:57:27 +08:00
    @kkk212 我有第一个问题: 真实用户 ID 一定不能暴露吗? 可否说说担忧的原因?
    kkk212
        25
    kkk212  
    OP
       2018-12-19 16:03:46 +08:00
    @jedrek 用户主页开放的话,比如防止按照用户 id,爬用户信息。
    jedrek
        26
    jedrek  
       2018-12-19 16:05:46 +08:00
    @jedrek 这个好解决, 用户 ID 不是连续自增的就可以了, 参考 instagram 的 ID 策略
    lawler
        27
    lawler  
       2018-12-19 16:32:30 +08:00
    用户 ID + 任意固定整数 -> 转 32 进制。

    例如 用户 id 1
    固定整数 987412312

    10 进制值是 987412313
    显示 id 是 tdldqp

    不定期更新任意固定整数。
    chinvo
        28
    chinvo  
       2018-12-19 16:36:19 +08:00 via iPhone
    @lawler #27 为了避免重复,你只能增大这个参数而不能减小,而且还需要一个专门的字段保存过去的 ID 对应的字符串
    lawler
        29
    lawler  
       2018-12-19 16:38:45 +08:00
    @chinvo 不需要啊。出站入站时反转 userid,换句话说,明天别人拿这个 id 访问这个页面的时候,就是别人的数据了。这个值不入库的。参数只要不是负值,任意值都没问题。
    zhengxiaowai
        30
    zhengxiaowai  
       2018-12-19 16:42:07 +08:00
    @kkk212 https://github.com/zhengxiaowai/shortuuid

    看看这个,实测百万无重复
    chinvo
        31
    chinvo  
       2018-12-19 16:45:02 +08:00 via iPhone
    @lawler #29 你得考虑持久化 URL 的问题,被检索的 URL、印刷的二维码和其他物料
    chinvo
        32
    chinvo  
       2018-12-19 16:45:25 +08:00 via iPhone
    我厂用 ksuid
    kkk212
        33
    kkk212  
    OP
       2018-12-19 16:53:04 +08:00
    @chinvo ksuid 位数长呀
    arthasgxy
        34
    arthasgxy  
       2018-12-19 16:58:30 +08:00
    好奇请教一下楼上各位,我司有类似的,只不过是纯数字,不知道是不是与你们同样的目的。
    每个用户,3、4 个 xxid,都是纯数字,有的长,有的短,一直不知道搞这么多有什么特别的意义?
    chinvo
        35
    chinvo  
       2018-12-19 17:06:20 +08:00 via iPhone
    @arthasgxy #34 大概是历史遗留问题,不同子系统甚至不同表里面用的 ID 不同
    chinvo
        36
    chinvo  
       2018-12-19 17:06:36 +08:00 via iPhone
    @kkk212 #33 emm,确实长了点
    chinvo
        37
    chinvo  
       2018-12-19 17:07:35 +08:00 via iPhone
    @kkk212 #33 snowflake 呢?或者自己实现类 ksuid,把 payload 从 128bit 减到 64bit
    arthasgxy
        38
    arthasgxy  
       2018-12-19 17:13:37 +08:00
    @chinvo 感谢回复。
    感觉上应该跟历史没啥关系。新项目,也是这样搞的。
    agdhole
        39
    agdhole  
       2018-12-20 02:04:55 +08:00
    转成 int 32/64? steam 是这么做的,不过很长
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5644 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 46ms · UTC 03:39 · PVG 11:39 · LAX 19:39 · JFK 22:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.