是否有任何通常被认为值得信赖的SHA-256 javascript实现?

jon*_*ono 75 javascript hash sha256 sha2

我正在为一个论坛写一个登录,并且需要在将它发送到服务器之前在javascript中对密码客户端进行散列.我无法确定哪些SHA-256实现我可以信任.我期待每个人都使用某种权威脚本,但我发现大量不同的项目都有自己的实现.

我意识到使用其他人的加密始终是信仰的飞跃,除非你有资格自己审查它,并且没有"值得信赖"的普遍定义,但这似乎是一种常见且重要的东西,应该有某种形式关于使用什么的共识.我只是天真吗?

编辑,因为它在评论中出现了很多:是的,我们在服务器端再次执行更严格的哈希.客户端散列不是我们在数据库中保存的最终结果.客户端散列是因为人类客户端请求它.他们没有给出具体原因,可能他们只是喜欢矫枉过正.

tyl*_*erl 94

斯坦福JS加密库包含SHA-256的实现.虽然JS中的加密并不像其他实现平台那样经过良好的审查,但这个问题至少部分是由Dan Boneh开发的,并且在某种程度上由Dan Boneh赞助,他是密码学中公认且值得信赖的名称. ,并且意味着该项目对实际知道他在做什么的人有一些疏忽.该项目也得到了NSF的支持.

但值得指出的是......
如果你在提交密码之前对客户端密码进行哈希处理,那么哈希就是密码,而原始密码就变得无关紧要了.攻击者只需要拦截散列以模仿用户,如果该散列未经修改地存储在服务器上,则服务器以纯文本形式存储密码(散列).

因此,您的安全性现在变得更糟,因为您决定将自己的改进添加到以前的可信方案中.

  • 没错,但它并不比发送密码更糟糕,密码可能在因特网的其他地方以明文形式使用. (43认同)
  • 但是,如果你再次在服务器上散列,这种做法是完全合法的. (25认同)
  • 我同意@NickBrunt.如果攻击者读取可能仅适用于此特定应用程序的随机哈希字符串,而不是可能在多个位置使用的原始密码,则会更好. (12认同)
  • @NickBrunt如果你在服务器上散列然后你没有保存传输的密码,但除了传输密码哈希之外你没有添加任何安全性,因为在任何一种情况下,你传输的是*真正的*密码. (11认同)
  • 我需要使用客户端哈希,因为我不希望服务器看到用户的明文密码.不是为了我提供的服务增加安全性,而是为了用户.我不仅保存了用恒定盐(每个用户不变,而不是全局)的用户哈希值,而且每次登录都使用随机会话盐重新散列它,这样可以在网络上提供一些额外的安全性来防止嗅探.如果服务器受到了损害,那么它的游戏结束了,但对于任何不真正p2p的东西都是如此. (9认同)
  • 我认为这与您关心为用户提供的服务水平有关。如果你在传输前对密码进行哈希处理,网络效应是你保护了整个社区,因为攻击者只能窃取你的双哈希密码,而不能使用它们登录另一个服务(假设你是 salt)。如果您的用户密码是在客户端未散列的情况下发送的,并且 mitm ssl strip 攻击绕过加密,那么攻击者将拥有纯文本的用户密码。如果该用户是医院管理员,您可能会错过在另一个系统中阻止严重的 hipaa 漏洞的机会。 (3认同)
  • @tylerl在发送到服务器*之前在客户端上哈希真实密码*甚至更安全,因为真正的文本密码永远不会打到网络,所以非常适合非https传输.此外,双重哈希不是必需的(虽然建议即salting),具有攻击者的哈希值没有值,因为服务器上的登录序列将/应始终在提供的值之前对数据存储进行比较. (3认同)

Vit*_*ich 28

https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest上,我发现这个使用内部js模块的代码片段:

async function sha256(message) {
    // encode as UTF-8
    const msgBuffer = new TextEncoder('utf-8').encode(message);                    

    // hash the message
    const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);

    // convert ArrayBuffer to Array
    const hashArray = Array.from(new Uint8Array(hashBuffer));

    // convert bytes to hex string                  
    const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('');
    return hashHex;
}
Run Code Online (Sandbox Code Playgroud)

请注意,crypto.subtle仅在您可以使用httpslocalhost- 例如您的本地开发时python3 -m http.server需要将此行添加到您的/etc/hosts: 0.0.0.0 localhost

重启 - 你可以打开localhost:8000工作crypto.subtle.

  • 对我来说失败(Chrome 88):`TypeError:无法读取未定义的属性'摘要'`。由于未知原因,“crypto.subtle”仅在 HTTPS 上下文中定义,这使得它不适合一般使用。 (4认同)
  • 内置的“加密”库应该可以正常工作:https://nodejs.org/dist/latest-v11.x/docs/api/crypto.html (3认同)
  • 这太棒了。谢谢你。Node.js 中是否有类似的 API 可用? (2认同)
  • @Tino “一般用途”通常意味着 HTTPS,现在我们已经进入了 21 世纪。 (2认同)

bri*_*out 16

Forge的SHA-256实现快速可靠.

要在几个SHA-256 JavaScript实现上运行测试,请访问http://brillout.github.io/test-javascript-hash-implementations/.

我的机器上的结果表明伪造是最快的实现,也比接受的答案中提到的斯坦福Javascript加密库(sjcl)快得多.

Forge大256 KB,但提取SHA-256相关代码会将大小减小到4.5 KB,请参阅https://github.com/brillout/forge-sha256


Rei*_*ica 10

不,没有办法使用浏览器JavaScript来提高密码安全性.我强烈建议你阅读这篇文章.在你的情况下,最大的问题是鸡蛋问题:

提供Javascript加密技术的"鸡蛋问题"是什么?

如果您不信任网络提供密码,或者更糟糕的是,不信任服务器不保留用户机密,则您不能相信它们提供安全代码.在你引入加密之前嗅探密码或阅读日记的同一攻击者只是劫持了加密代码.

[...]

为什么我不能使用TLS/SSL来提供Javascript加密代码?

您可以.它比听起来更难,但你可以安全地使用SSL将Javascript加密传输到浏览器.问题是,通过SSL建立安全通道后,您不再需要Javascript加密; 你有"真正的"密码学.

这导致了这个:

在Javascript中运行加密代码的问题在于,实际上加密所依赖的任何函数都可以被用于构建托管页面的任何内容静默地覆盖.加密安全性可以在过程的早期(通过生成伪随机数,或通过篡改算法使用的常量和参数)或稍后(通过将关键材料激活回攻击者)或在最可能的场景中撤消.---完全绕过加密.

任何Javascript代码都没有可靠的方法来验证其执行环境.Javascript加密代码不能问,"我真的在处理一个随机数生成器,还是一些攻击者提供的传真​​?" 它当然不能断言"除了我作者所赞同的方式之外,没有人被允许对这个加密秘密做任何事情".这些是通常在使用加密的其他环境中提供的两个属性,在Javascript中它们是不可能的.

基本上问题是这样的:

  • 您的客户不信任您的服务器,因此他们希望添加额外的安全代码.
  • 该安全代码由您的服务器(他们不信任的服务器)提供.

或者,

  • 您的客户不信任SSL,因此他们希望您使用额外的安全代码.
  • 该安全代码通过SSL提供.

注意:此外,SHA-256不适用于此,因为它非常容易强制使用未加密的非迭代密码.如果您决定这样做,请查找bcrypt,scryptPBKDF2的实现.

  • 避免系统管理员访问用户密码是合理的,因此客户端中的散列会阻止DBA或其他IT专业人员查看用户密码并尝试重复使用它来访问其他服务/系统,因为很多用户会重复他们的密码. (3认同)
  • 这是不正确的。可以通过在客户端进行散列来提高密码安全性。只要在服务器端使用 PBKDF2 之类的东西,SHA-256 就不适合,这也是错误的。第三,虽然 matasano 的文章包含了有用的见解,但其中的妙语是错误的,因为我们现在有了可以从根本上改变先有鸡还是先有蛋的问题的浏览器应用程序。 (2认同)
  • 你应该在客户端上使用PBKDF2.对客户端javascript加密的愤怒假设初始页面和后续请求具有相同的安全属性.对于初始页面单独安装且是静态的浏览器应用程序,显然不是这样.任何具有缓存永久语义的页面也不是这样.在这些情况下,TOFU与安装客户端程序时完全相同.在更复杂的设置中也是如此,其中静态和动态页面的服务在服务器上是分开的. (2认同)
  • @Xenland 鸡和蛋的问题与您发送的请求没有任何关系。问题是您的客户端正在使用 JavaScript 代码**它通过不安全的连接**下载**来执行安全工作。将 JavaScript 安全发送到 Web 浏览器的唯一方法是通过 TLS 为其提供服务,一旦您这样做了,您就无需再执行任何其他操作,因为您的连接已经是安全的。如果您使用的是攻击者可以替换的 JavaScript 代码,那么您的协议是什么并不重要。 (2认同)

cob*_*lla 10

我发现这个实现非常容易使用.还有一个慷慨的BSD风格许可证:

jsSHA:https://github.com/Caligatio/jsSHA

我需要一种快速方法来获取SHA-256哈希的十六进制字符串表示.它只花了3行:

var sha256 = new jsSHA('SHA-256', 'TEXT');
sha256.update(some_string_variable_to_hash);
var hash = sha256.getHash("HEX");
Run Code Online (Sandbox Code Playgroud)


Dan*_*van 7

对于那些感兴趣的人,这是用于创建SHA-256哈希的代码sjcl:

import sjcl from 'sjcl'

const myString = 'Hello'
const myBitArray = sjcl.hash.sha256.hash(myString)
const myHash = sjcl.codec.hex.fromBits(myBitArray)
Run Code Online (Sandbox Code Playgroud)

  • 对于那些想要在那里使用解决方案的人,这应该包含在已接受的答案中。(哎呀,即使他们自己的文档也没有这样的片段) (7认同)
  • 这是最好的答案。我正在尝试加密解决方案,但它对我不起作用。 (2认同)