V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
这是一个专门讨论 idea 的地方。

每个人的时间,资源是有限的,有的时候你或许能够想到很多 idea,但是由于现实的限制,却并不是所有的 idea 都能够成为现实。

那这个时候,不妨可以把那些 idea 分享出来,启发别人。
chenjia404
V2EX  ›  奇思妙想

一个抗脱库的密码哈希方法

  •  
  •   chenjia404 · 2023-07-14 19:43:56 +08:00 · 2427 次点击
    这是一个创建于 502 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我之前做过一个方案: 哈希(用户名+密码+网站名)发送给服务器,服务器拿到提交的哈希和用户名,再哈希(用户名+密码+网站名+盐),把最后一步的哈希存在一张哈希表里面,下次用户登录的时候,只需要验证哈希表中是否有元素即可。 修改密码的时候修改用户的盐,写入新的哈希记录就行了,而且哈希表越来越大,每个网站的哈希表都不一样,泄露也没有办法跑彩虹表。 哈希函数只要是在 sha1 以上的,基本上冲突的可能性就很小。 这个方案也不需要提交明文密码到服务器,过安全测评也好过。

    31 条回复    2024-10-02 11:25:20 +08:00
    RatioPattern
        1
    RatioPattern  
       2023-07-14 21:11:42 +08:00
    直接上感觉有问题,有没有大佬解析下
    dic
        2
    dic  
       2023-07-14 21:25:08 +08:00
    直接 Bcrypt 就行了。
    dcsuibian
        3
    dcsuibian  
       2023-07-14 21:39:44 +08:00 via Android
    修改密码的时候修改用户的盐是什么意思?盐不应该就一个么
    duke807
        4
    duke807  
       2023-07-14 21:40:12 +08:00 via Android
    仅密码加网站名做 sha 运算和比对就行了
    用户名不需要
    这样不会有碰撞
    chenjia404
        5
    chenjia404  
    OP
       2023-07-14 22:48:13 +08:00
    @dcsuibian #3 每个用户一个盐,修改密码的时候就更新盐。
    chenjia404
        6
    chenjia404  
    OP
       2023-07-14 22:48:38 +08:00
    @duke807 #4 如果没有用户名,怎么确定这个哈希是这个用户呢?
    rekulas
        7
    rekulas  
       2023-07-14 22:59:39 +08:00   ❤️ 2
    我看了半天,你这个所谓的方案跟正常加盐 hash 没有区别

    hash(用户名+密码+网站名+盐)
    hash(密码+盐)

    如果你觉得这两个安全性不一样的话只能说明你的盐有问题
    duke807
        8
    duke807  
       2023-07-15 08:40:58 +08:00 via Android
    @chenjia404 用户名 明文 传输到服务器
    chenjia404
        9
    chenjia404  
    OP
       2023-07-15 12:32:24 +08:00
    @rekulas #7 这个没有明文密码到服务器,以及不会被彩虹表破解,用户密码不会被反向破解出来。
    googlefans
        10
    googlefans  
       2023-07-15 14:01:48 +08:00
    以后直接建内容站 直接静态
    不用数据库了
    lete
        11
    lete  
       2023-07-15 17:22:49 +08:00
    了解一下: https://unpwd.github.io , 用户直接自己加密,就连你服务器都不知道我用户的明文密码
    lucybenz
        12
    lucybenz  
       2023-07-15 21:00:10 +08:00
    说复杂了 简单讲就是做了密码字段客户端加密
    rekulas
        13
    rekulas  
       2023-07-15 21:36:49 +08:00
    @chenjia404 其实前端传输密码 hash 早就普及开了,至于破解这个只要有足够安全的盐,你在里面再加入其它别的什么难度并没有提高或降低
    chenjia404
        14
    chenjia404  
    OP
       2023-07-15 23:58:48 +08:00 via Android
    @rekulas 你没有看明白,这个方法,你没有办法反推用户密码
    dode
        15
    dode  
       2023-07-16 01:33:14 +08:00 via Android
    现在有新接口了,客户端直接使用私钥验证信息,服务器端存储每个用户设备的公钥
    8E9aYW8oj31rnbOK
        16
    8E9aYW8oj31rnbOK  
       2023-07-16 14:11:49 +08:00 via Android
    想法不错,多了一层“主观逻辑加密”
    patrickyoung
        17
    patrickyoung  
       2023-07-16 19:36:07 +08:00 via iPhone
    @chenjia404 #14 并没有没有办法这一说,只是你主观安全而已,建议系统的重学密码学。整个方案就是普通的加盐 hash
    iX8NEGGn
        18
    iX8NEGGn  
       2023-07-16 21:56:45 +08:00 via iPhone
    你这不就是把(用户名、网站名)当作盐而已嘛,还没有直接用随机的盐安全
    tt7
        19
    tt7  
       2023-07-17 00:09:57 +08:00
    @chenjia404 #9 明文密码,和没有随机数的密码 hash 有什么区别吗?
    chenjia404
        20
    chenjia404  
    OP
       2023-07-17 03:07:57 +08:00   ❤️ 1
    @patrickyoung #17 传统的加盐 hash ,保存了哈希和用户的对应关系,我这个没有保存用户和哈希对应关系。
    Liyuu
        21
    Liyuu  
       2023-07-17 23:36:24 +08:00
    也就是说'网站名'可以换成任意一个常量,相当于加了一个没有存在库里的盐,这样吗?
    dallaslu
        22
    dallaslu  
       2023-07-18 14:20:19 +08:00
    大概是这样吧?

    * 客户端计算 hash(user+pass+site),得出 user_hash
    * 注册时客户端将 user 和 user_hash 发送到服务器,服务器建立 user 并创建对应 salt ,计算 hash(user+user_hash+site+salt) 得出 auth_hash ,将其存入一个与 user 无关联的表中
    * 登录时服务器根据 user 查询 salt ,并计算 auth_hash ,如其在表中存在,则验证通过
    * 修改密码时,根据旧密码计算出旧的 auth_hash 并删除之,然后创建新 salt 并保存新 auth_hash

    被拖库时,攻击者只能看到 user 和对应 salt ,以及一堆无任何标识的 auth_hash ,既不能查表,也不能破解。

    上面各位提到网站名 site ,其实在做 auth_hash 时用 hash(user+user_hash+salt) 即可,site 在此没有必要。这个方案主要就两点,客户端不发真实密码、服务器不保存 auth_hash 与用户的关联。

    客户端发 hash 不发密码的出发点是什么呢?是怕被中间人嗅探、服务器日志记录吧,尽管保护了真实密码,但 user_hash 每次使用时都是不变的,在此网站也等同于密码,只起到有限的保护作用。

    服务器不存 auth_hash 与用户的关联,的确将拖库后的破解难度提升了用户数量的倍数,如果有十万用户,从 auth_hash 暴力破解指定用户的 pass ,最多需要计算 256^20*256^20*100000 次
    chenjia404
        23
    chenjia404  
    OP
       2023-07-18 20:27:38 +08:00
    @dallaslu #22 旧的 auth_hash 不删除,这个表数据越多越好
    dallaslu
        24
    dallaslu  
       2023-07-19 10:44:24 +08:00
    @chenjia404 即使这个策略奏效,也只是将 256^40 变成 256^43 ,「几乎不可能」乘以十万也是「几乎不可能」
    chenjia404
        25
    chenjia404  
    OP
       2023-07-19 16:10:48 +08:00 via Android
    @dallaslu 恩,不过确实无法反向破解明文密码了,auth_hash 表公布都没有影响。
    stamhe
        26
    stamhe  
       2023-09-09 10:12:26 +08:00
    @dode 嗨,想了解一下,你这个是你们项目有在使用的东西么?
    dode
        27
    dode  
       2023-09-09 21:22:42 +08:00
    @stamhe 我们不涉及这个,我看到谷歌在用了
    stamhe
        28
    stamhe  
       2023-09-10 16:45:21 +08:00
    @dode google 和 apple 他们接入的是 fido alliance 的 passkey 方案,这个方案是个残疾。不能用于工业应用。
    CLMan
        29
    CLMan  
       57 天前
    自从加盐哈希流行以后,安全界为啥还要建议使用 Bcrypt 、argon2 这些密码存储专用的哈希算法呢,无非是担心现有及以后的硬件暴力破解通用哈希算法太快。至于彩虹表,已经是上个过时版本了。

    而你认为设计很好的点“ auth_hash 与 user 并非一一对应”,反而是最大的漏洞,因为它们其实是 N:1 的关系( N 指 auth_hash 表的大小),意味着暴力破解时,可以碰撞的哈希值有 N 个。“这个表数据越多越好”,意味着破解的难度越低。

    很多人以为,密码存储哈希值是避免用户的明文密码泄露,其实不然,是避免应用的明文密码泄露。如果是前者,那客户端密码 hash 早就流行开来了,还不至于成为开发者之间的争论点。对于后者,客户端密码 hash 毫无作用。
    chenjia404
        30
    chenjia404  
    OP
       56 天前
    @CLMan #29 "可以碰撞的哈希值有 N 个,意味着破解的难度越低",这里实际上碰撞难度没有下降,还是和哈希函数的强度正相关。
    CLMan
        31
    CLMan  
       56 天前
    @chenjia404 我懂你的意思了,因为 hash 函数的特点,1:N 这种对应关系,其中 N-1 个是无效值,即碰撞就是白费力气,那你的方案确实有趣。当然由于没有知识背景,我无法判断这种说法是否正确。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3109 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 13:37 · PVG 21:37 · LAX 05:37 · JFK 08:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.