V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
drymonfidelia
V2EX  ›  信息安全

从原理上分析,把明文进行 100 轮 [SHA512->SHA256] 这样哈希计算,随机性会比直接 SHA256 更差吗?运算后结果可能性不都是 2^256 种吗?照这么说的话加 salt 也会影响随机性?

  •  
  •   drymonfidelia · 72 天前 · 2982 次点击
    这是一个创建于 72 天前的主题,其中的信息可能已经有所发展或是发生改变。

    记得在本站一篇讨论在前端给用户密码加密是不是脱裤子放屁的帖子中有人说把明文变长后 hash 会一定程度上影响随机性,从而导致安全性降低,当时我就很怀疑这种说法,觉得毫无根据,当时没空发帖,现在又想到了这个问题,并且想改成更极端的情况,先更长的 SHA512 再 SHA256 再 SHA512 ,重复 100 轮。

    33 条回复    2024-09-23 08:52:59 +08:00
    drymonfidelia
        1
    drymonfidelia  
    OP
       72 天前
    我的想法既然每一位单独发生改变都一定会影响 SHA256 的运算结果,SHA256 运算结果的每一个 bit 应该都是等可能性的,不管怎么对明文取样,只要每一个明文 bit 取样的权重一致,都不应该影响随机性(不懂怎么表达,大概是这样)
    YGHMXFAL
        2
    YGHMXFAL  
       72 天前 via Android
    目的呢?

    如果想校验数据完整性,只需要选择强壮地摘要算法 HASH 一次即可

    如果想增加攻击者穷举密码的计算成本,有专门为这一场景设计地、专用定制硬件也望洋兴叹地[慢 HASH]算法,例如 scrypt/argon2

    应该是在 SOF 看过一帖,这一套[多轮 HASH]或者类似地[多种算法嵌套 HASH]都是不推荐地方案,原理我也没看懂,结论就是会增加碰撞地可能性,也就是说反而降低了安全性
    cxtrinityy
        3
    cxtrinityy  
       72 天前 via Android   ❤️ 1
    emmm ,哈希是摘要,不是加密,不可逆的,密码 hash 可以避免你保存的用户密码被人脱库直接暴露吧,所以你也不需要保存用户密码,下次拿了密码再哈希一遍对上了就是密码正确
    随机性这个没看明白,哈希和随机性有啥关系?算法是公开的呀,同样的算法,同样的输入,只会有同样的输出,sha256 碰撞的可能性已经很小了吧,只要不是常用的那些密码,一般很难撞上。暴力轮询也只是把常用的密码 hash 后记下来作为词典查询罢了。
    至于明文长度,不知道你说的原帖具体咋说的,不过应该和 hash 结果分布没啥关系,毕竟不管啥明文也是要先切割补位的
    drymonfidelia
        4
    drymonfidelia  
    OP
       72 天前
    @YGHMXFAL #2 目的是前端 hash 满足 /t/1025454 这里面的一部分人对形式主义安全的要求(他们觉得服务端不应该收到能还原回明文的密码,但是前端加密完全阻止不了被劫持或者被恶意浏览器插件直接注入 js 读取输入框里的明文密码)。服务端收到客户端的提交的 hash 后加盐二次 hash 后再入库防止数据库泄露了有人使用数据库里的 hash 来登录网站。
    julyclyde
        5
    julyclyde  
       72 天前
    多轮 hash 更容易碰撞吧
    你都明知道后一轮的输入是更小的集合了
    geelaw
        6
    geelaw  
       72 天前
    用函数作用于一个输入,那么输出是固定的,没有任何随机性。如果输入本身是随机的,那么作用函数之后依然是随机的,但熵不会增加,而且非常明显的例子是把具有 1024 bits 熵的输入用楼主提出的两种方式作用,得到的结果熵必然不能超过 256 bits 。

    当然,经过函数作用后,“计算熵”可以增加,然而标准模型下很难分析 SHA-512 和 SHA-256 对输入的计算熵产生何种影响。

    只考虑抗碰撞的话,多个函数复合的抗碰撞能力当然不超过最里面的那个的。
    0o0O0o0O0o
        7
    0o0O0o0O0o  
       72 天前
    多轮 hash 不增加熵,所以只要输入固定就不影响"随机性",影响的只是攻击者的成本
    https://www.google.com/search?q=site%3Acrypto.stackexchange.com+KDF+entropy
    gbadge
        8
    gbadge  
       72 天前
    两轮肯定会比一轮安全,拿被脱裤的站举例,相当于加盐处理了
    FengMubai
        9
    FengMubai  
       72 天前
    @drymonfidelia #4 这个问题可以规约成:你是否认为服务提供方有 安全义务 保障当自身安全系统被攻破时,用户在其他站点的数据不受影响?
    drymonfidelia
        10
    drymonfidelia  
    OP
       72 天前
    @FengMubai 你说的是在前端 hash 明文密码吗?理由我已经给了,就算在前端加密了,攻击者如果破解了我平台的服务器,也可以往登录页面插入记录明文密码的恶意 js ,把密码 post 到他们的服务器,因此前端加密并不能阻止保障当自身安全系统被攻破时,用户在其他站点的数据不受影响。就算在前端没有加密(目前绝大部分网站都是这样),只要我数据库里存的密码是 hash 过的,自身安全系统被攻破时,用户在其他站点的数据也不受影响。
    FengMubai
        11
    FengMubai  
       72 天前
    @drymonfidelia #10 插入恶意代码这件事,至少你还可以拔网线
    FengMubai
        12
    FengMubai  
       72 天前
    理论上会降低随机性,但实际上不会。

    首先,你的随机性是由输入源决定的,它的空间大小是无穷的。经过一轮哈希后,空间大小变成了 256 位(以 SHA256 为例),理论上随机性是下降了的。但是,目前 SHA256 还没有发现碰撞,所以实际上没有降低随机性。而如果你用的 MD5 ,那实际上肯定也是降低了。

    为什么要做多轮哈希?为了增大彩虹表攻击的难度
    rekulas
        13
    rekulas  
       72 天前   ❤️ 2
    作为一款加密算法,如果随机性都做不到稳定那也太拉了,怎么可能被选为标准

    不会增加随机性,但会增加安全性
    jim9606
        14
    jim9606  
       72 天前
    主要问题就是多轮迭代会缩小值域,你要是用短的摘要(例如只有 64bit 的 MD5 )就会比较要命,使用截短 hash 也会有一样的问题,如果不幸没有使用等长时间复杂度的 hash 校验方法也会削弱 hash 的保护能力。
    还有考虑密文泄露的场景(服务器数据库泄露),如果没加 salt ,攻击者可以预先构造彩虹表,你这种 100 轮 hash 是用同数量级的性能代价提高攻击代价,用 100 倍计算复杂度换 100 倍攻击难度,这是不划算的,还是加 salt 好。
    直接原文拼接 salt 有导致长度拓展攻击的问题,所以不是搞密码学的还是老实用封装好的 HMAC 就好了。
    gbadge
        15
    gbadge  
       72 天前
    试想一下一个 80 亿用户规模的数据库将密码按照 OP 的说法处理,就算被脱裤,离线暴力破解的难度也会加大,首先对方可能不会想到,其次解密工作量翻倍,安全肯定是更安全
    restkhz
        16
    restkhz  
       72 天前   ❤️ 1
    经常看到这种争论,我平时很少在这种争论中说话。

    回复 OP 一楼:理论上,对于 SHA-256 这种成熟可靠的算法,多次迭代不会有问题。实际上很多地方有在用这种做法。
    回复 OP 四楼:我也同样不认为在实践中对于普通业务 https 下还前端 hash 密码有多好的安全性,除非是某些特别场景。前端加密能保护的东西太有限了。
    回复 OP10 楼:是这样的。如果服务器被 pwn 那么最重要的还是数据库里的东西。该加盐的加盐就好了。

    HTTPS 后前端 hash 到底保护啥了?防止 HTTPS 被破解?还是服务器那边 https 解密后的过程?如果我都拿下服务器了我为什么不注入脚本钓鱼?

    我看过 11 楼在另一个帖子里自己发明的方法,是好的想法,但有点鸡肋。拔网线了意味着黑客同时也不可能嗅探到 https 流量。只能对着之前拖的库里的 hash with salt(应该有两层 salt) 干瞪眼。但是可能只有极其极端情况下才有用。其实同样的,我曾经也想过一样的问题。但是我的对策是 pwd+salt+challenge-response 。
    另外纠正一下,真正对彩虹表有完全克制作用的是 salt 而不是迭代。迭代只是减缓破解速度。

    实践上呢?
    黑客拖库后通常不是搞什么集群 FPGA ,ASIC 暴力破解,而是直接提交给某个老牌网站批量查。
    没经验的搞不出来就放弃了,有经验的会看代码,然后发现批量破解成本太高,破半天搞出几个弱密码。
    一般黑客也不会劫持 web 服务软件去读用户请求,还不如上一个 xmr 矿机搞 ddos 闷声发大财(其实基本都是 bot 在做)除非你的用户价值非常非常高,高到别人愿意花多少万来专门搞你的用户。

    唉,有时候禁止用户用弱密码反而可能是一个不错的方案。
    dzdh
        17
    dzdh  
       72 天前
    一次 hash ,是任意字符输入的组合的 hash 结果。还不限长度。

    一次 hash 后,可选字符只剩下了 0-9a-f ,还限制长度。

    无论多少轮,最后碰撞只剩下 0-9a-f 还限定位数 的范围。

    就单从概率来说也并不比一次 hash 安全。
    dzdh
        18
    dzdh  
       72 天前
    如果是密码,bcrypt/scrypt/argon2(i|d) 足够。

    校验完整性,任何 hash 一次足够。
    tool2dx
        19
    tool2dx  
       72 天前
    正常的 hash 算法,大部分都是随机的。个别 bit 随机性测试可能结果稍微弱一点,但是这种是完全可以忽略的。

    密码 hash 还有一个问题,就是没加 padding 。以至于时间足够,是可以暴力推导的。比如用户密码 abcd ,你加 5 层 sha256 并加盐,结果也恒定,可以通过彩虹查找表得到明文。但如果用户名密码加了随机 padding ,就如同 rsa 加密标准那样,密码从 4 字节变成了 256 字节,那就推不出来了。

    和 1 个字节 hash 后,和 1G 文件 hash 后,hash 长度一致,蕴含的内容意义完全不一样。
    InkStone
        20
    InkStone  
       72 天前
    多轮 hash 的目的是增加攻击者的计算成本。就本身分布和单轮 hash 是一样的
    rekulas
        21
    rekulas  
       72 天前
    @dzdh 你自己都说了是 hash 了,看下源码就知道任何输入都会映射到固定区间,在数学上不存在输入更复杂就更安全的情况


    所以“任意字符输入的组合的 hash 结果” 跟 hash 的结果再次 hash 仅从概率上是一样安全的
    edward1987
        22
    edward1987  
       72 天前
    @rekulas #21 应该是有影响随机性的。比如先 hash 成 256 个字符的 A ,A 再 hash 成 512 字符的 B , 这时候 B 最多只有 16^256 种结果,但是如果是不限制输入,B 有 16^512 种结果
    rekulas
        23
    rekulas  
       72 天前
    @edward1987 come on, 你这个推理有点钻牛角尖了,我说的“ hash 的结果再次 hash”当然是指同一个 hash 算法,包括输入应该是同样范围的

    你这个我再翻译下,相当于把任何输入映射为 0-9 的数字,再对这个数字进行 hash ,那 hash 结果当然只有 9 种

    如果你第二次 hash 的算法也是同一种,那数学安全性是没有区别的
    rekulas
        24
    rekulas  
       72 天前
    @rekulas 抱歉是 10 种
    edward1987
        25
    edward1987  
       72 天前
    @rekulas 如果是相同算法,那我赞成你说的。我是看楼主的提问里面确实是用不同 hash 算法 [并且想改成更极端的情况,先更长的 SHA512 再 SHA256 再 SHA512 ,重复 100 轮]
    rekulas
        26
    rekulas  
       72 天前
    @edward1987 好吧,那确实是的,我只是针对上面的评论回复,不是针对 op 的 hash 算法变化的情况
    ryan4yin
        27
    ryan4yin  
       71 天前
    本质上仍旧是成本跟安全的平衡,客户端弄个 Hash 就加几行代码的事,就能提升整条链路的安全性,何乐而不为呢?我不明白这事有什么可争的。
    ryan4yin
        28
    ryan4yin  
       71 天前   ❤️ 1
    #4

    「前端加密是形式主义安全的要求,前端加密完全阻止不了被劫持或者被恶意浏览器插件直接注入 js 读取输入框里的明文密码。」

    没有什么技术能解决所有问题啊,你不能因为一项技术没解决掉个别问题,就认为它完全是形式主义。
    类似深信服之类的技术在你电脑里装它的证书从而监控你所有 HTTPS 流量的明文内容,而前端加密至少能保证你的明文密码不会泄漏给公司。
    上面也有 v2 友提了,明文密码泄漏要比 Hash 泄漏严重得多,用户其他站点也可能因为你们前端没做 Hash ,被黑客一举攻破。

    另外一点是,HTTPS 并不总是安全的,不要总觉得用了 HTTPS 就多安全,TLS 从 SSL1.0 迭代到现在 TLS1.3 ,一堆的弱密码,实际安全性还是得看客户端与服务端的两边的具体配置。

    对 OP 引用的前一个帖子一些观点的反驳:

    1. https + 后端加密入库足够安全:这得看具体的流量链路架构,单纯从你前后端看可能感觉都很安全,但中间是否过了 CDN 加速?是否做了 TLS 的边缘端及早截止( https://0xffff.one/d/968 )?即使你做这个决定时系统是够安全的,但 infra 团队不一定知道啊,他们对中间这些链路做的任何变更都可能会破坏你的安全假设。所以为了避免沟通成本,强制前端做 Hash 是很合理的选择。
    2. 增加开发成本,没必要:前端对密码做个 Hash 就几行代码的事,调用个现成的库就行,这个东西很复杂吗???要增加多少开发成本???
    3. 加密后导致密码强度的下降(因为密文的信息熵下降了):所有 ASCII 字符数字符号加一起是 94 个,简单计算你的密码需要至少 40 个字符,它的排列数量才能超过 2^256 钟,我还从来没见过谁的密码有这么复杂...


    如果你是在什么无所谓安全的小公司工作,公司也没啥要求,那你确实怎么折腾都无所谓,不用管什么哪里加密,想怎么写就怎么写,功能实现了就 OK. 但我个人还是建议养成一点技术上的品味。
    yianing
        29
    yianing  
       71 天前 via Android
    会减小随机性,摘要是多对少的,你用少的结果再去摘要,值域只会更少
    zizon
        30
    zizon  
       71 天前
    f_1(f_2(f_3....f_n(input))) 等价于存在一个 g(input)
    g 的离散性直觉上取决于 f chain 中的离散性分布.

    直观的例子就是传统机器学习所谓收敛 local minimal 的概念.

    比如如果你其中一个或者几个 f 在空间分布式存在某种形式的倾斜,那么逻辑上就是多余某个 f_k 的输出存在一定的偏向性.

    极端情况累积下,可能存在你的 f chain 的等价形式 g 就是一个常数.
    skallz
        31
    skallz  
       71 天前
    @drymonfidelia 我猜前端加密应该是避免中间人攻击?之前做金融行业的网站的时候,前端就会对密码采用动态加密以防止中间人攻击,为什么这么做?因为真的有人被攻击了。。。
    restkhz
        32
    restkhz  
       71 天前   ❤️ 1
    @ryan4yin 我认为你说的有道理。这种场景这么做是有意义的。送一个感谢。

    摸个大鱼,写个长文。
    很多人都在说:
    ”多次迭代 hash 很多人都在说第二次输入范围变小“。我就不一一 at 了。

    @YGHMXFAL 关于多次迭代的问题我先说,多算法嵌套的问题我下文说。
    我们来做一个脑内实验:
    如果我们用同一个 hash 算法,进行几乎[无穷]多次迭代,那么一定会在某一次碰撞,对吧?毕竟 hash 值域空间有限。

    而且,根据鸽巢原理,随着迭代次数增加,和之前迭代过程中 hash 碰撞概率也随之增加。比如迭代了 1 亿次,
    这个碰撞来临的可能比我们预想的快(生日悖论)。

    我们这样写:a 经过 hash 成为 b ,b 再 hash 成 c ,我们在这里写成 a->b->c

    a->b->c->d->e->f->g

    到此为止,一切都好。但是在下一时刻,g 经过 hash 后发生了碰撞成了[e]
    于是最后这个 hash 就成了

    a->b->c->d-> e->f->g-> e->f->g-> e->f->g-> e->f->g......

    你会发现这个 hash 碰撞后会不可避免地陷入了一个循环。
    最后结果就在 efg 这三个结果之间,实际上的值域变小。此后再多迭代次数也没有意义。我只要知道这个环里的元素 efg ,知道迭代次数,我们就可以推算出具体哪个元素可以构成碰撞。

    比如上面就是 hash(a)*8=f, 我们不知道 a, 但是我们可以 8mod3=2 ,hash(g)*8=f=hash(a)*8 这样构造出碰撞。

    然而对于一个健壮的 hash 算法来说出现上述情况很难,或者说你只迭代一千次一万次完全没问题。甚至就算有碰撞,这个环也可能大到难以探测。


    再说组合不同算法:
    假设一个不安全 hash 叫做 weak, 只输出 1 位。不是 0 就是 1.碰撞概率五五开。
    你 sha-512 然后 weak ,会怎么样?碰撞概率依旧五五开。组合 hash 算法安全性取决于最差的那个 hash 。调换顺序也没用。

    @gbadge 不可以替代 salt 。多次迭代会增加算力消耗没错。salt 让彩虹表无法复用,而且在空间和计算上都制造难度。
    @jim9606 长度扩展攻击...可能不会让破解变得容易。至少我不知道。因为长度扩展攻击可以在我只知道 MD5(pwd)和 salt 的情况下算出 MD5(pwd+salt)但是我的确不知道怎么算 pwd 或者 MD5(pwd)...不管怎样,反正 MD5 ,SHA-1 的确就别再用了。

    其他人懒得一个个回复了。

    最后好好回复给 OP:
    理论上:OP 的做法意义不大。虽然应该不会更不”随机“,但是安全性取决于最差的那个算法。而且只要有一个算法有问题那整个都变弱。迭代是有意义的,代价就是可以忽略的碰撞概率增加。

    实际上:OP 的做法很有意义。黑客喜欢用现成的服务比如 hash 查询。黑客看到你这种骚操作很可能骂娘后直接放弃。但是弱密码依旧有可能被破解。
    把黑客恶心死,也是一种安全。

    多次迭代拖慢暴力,奇葩嵌套无法查询,加盐对抗彩虹表,密码策略防止弱密码对抗字典。

    (所以...为什么不用 bcrypt 这些呢?)
    yukunyi
        33
    yukunyi  
       54 天前
    主要是防彩虹表
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2923 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 03:25 · PVG 11:25 · LAX 19:25 · JFK 22:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.