是否有任何通常被认为值得信赖的 SHA-256 javascript 实现?
Posted
技术标签:
【中文标题】是否有任何通常被认为值得信赖的 SHA-256 javascript 实现?【英文标题】:Are there any SHA-256 javascript implementations that are generally considered trustworthy? [closed] 【发布时间】:2013-08-22 17:32:27 【问题描述】:我正在为论坛编写登录名,并且需要在将密码发送到服务器之前在 javascript 中对客户端密码进行哈希处理。我无法确定我真正可以信任的 SHA-256 实现。我期待有某种权威的脚本,每个人都在使用,但我发现很多不同的项目都有自己的实现。
我意识到使用其他人的加密货币总是一种信仰的飞跃,除非你有资格自己审查它,而且“值得信赖”没有普遍的定义,但这似乎是一件很普遍和重要的事情,应该就使用什么达成某种共识。我是不是太天真了?
编辑,因为它在 cmets 中出现了很多:是的,我们再次在服务器端进行更严格的哈希。客户端散列不是我们保存在数据库中的最终结果。客户端散列是因为人类客户端请求它。他们没有给出具体原因,可能他们只是喜欢过度杀伤。
【问题讨论】:
不想跑题,但你为什么要在客户端散列密码? @ddyer 甚至没有接近。 “不要自己动手”适用于发明自己的算法、编写自己的算法实现、在加密算法之上开发自己的协议,或者几乎任何上述用作高级别的东西可用的抽象。如果你认为坚持一个安全的核心是安全的,并且只编写胶水代码,那么你将度过一段糟糕的时光。 如果您使用没有挑战/响应协议的哈希密码,那么哈希密码就是密码,它实际上与以明文形式传输密码相同。 @ddyer 保护用户的明文密码对于他们可能使用的所有其他网站是有一定价值的,如果不是特别是我们的网站。这是一个简单的解决方法,可能对我们没有帮助,但如果我们在某个地方搞砸了,可能会帮助用户。就像我说的,客户请求,即使我想,我也无能为力。 @Anorov 我非常愿意改变我的想法:) 但在这种情况下,我真的不明白你的观点是如何适用的。我们对密码进行两次哈希处理:一次在客户端使用简单的 SHA-256,一次在服务器端使用要求更高的密码。第一个在 MITM 或类似情况下保护明文,第二个用于暴力保护。即使您掌握了数据库和管理员哈希,您也无法直接使用它来验证登录。 【参考方案1】:过时:许多现代浏览器现在都对加密操作提供一流的支持。请参阅下面的Vitaly Zdanevich's answer。
Stanford JS Crypto Library 包含 SHA-256 的实现。虽然 JS 中的加密并没有像其他实现平台那样经过严格审查,但这个平台至少部分由Dan Boneh 开发,并在一定程度上由Dan Boneh 赞助,Dan Boneh 在密码学,这意味着该项目受到真正知道自己在做什么的人的监督。该项目也得到了NSF的支持。
值得指出,但是...... ...如果您在提交密码之前在客户端散列密码,那么 散列就是密码,原始密码变得无关紧要。攻击者只需要拦截哈希来冒充用户,并且如果该哈希未经修改地存储在服务器上,那么服务器将以明文形式存储 true 密码(哈希) -文本。
因此,您的安全性现在更糟,因为您决定 add your own improvements 采用以前受信任的方案。
【讨论】:
如果你在服务器上再次哈希,这种做法是完全合法的。 @NickBrunt 如果你在服务器上散列,那么你没有保存传输的密码,但是除了传输原始密码而不是传输密码散列之外,你没有添加任何安全性,因为在任一如果您传输的是真实密码。 是的,但这并不比以明文形式发送可能在 Internet 上其他地方使用的密码更糟糕。 我同意@NickBrunt。攻击者最好读取一个可能只适合该特定应用的随机哈希字符串,而不是可能在多个地方使用的原始密码。 我需要使用客户端散列,因为我不希望服务器看到用户的明文密码。不是为了增加我提供的服务的安全性,而是为了用户。我不仅保存了用恒定盐(每个用户恒定,而不是全局)加盐的用户哈希,而且每次登录时都用随机会话盐重新哈希它,这确实在网络上提供了一些额外的安全性来防止嗅探。如果服务器受到威胁,游戏就结束了,但对于任何不是真正 p2p 的东西都是如此。【参考方案2】:在https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest我发现了这个使用内部js模块的sn-p:
async function sha256(message)
// encode as UTF-8
const msgBuffer = new TextEncoder().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 => b.toString(16).padStart(2, '0')).join('');
return hashHex;
请注意,crypto.subtle
仅适用于 https
或 localhost
- 例如,对于使用 python3 -m http.server
的本地开发,您需要将此行添加到您的 /etc/hosts
:
0.0.0.0 localhost
重新启动 - 你可以打开 localhost:8000
与工作 crypto.subtle
。
【讨论】:
这太棒了。谢谢你。 Node.js 中是否有类似的 API? 内置的“加密”库应该可以正常工作:nodejs.org/dist/latest-v11.x/docs/api/crypto.html 对我来说失败了(Chrome 88):TypeError: Cannot read property 'digest' of undefined
。由于未知原因,crypto.subtle
仅在 HTTPS 上下文中定义,因此不适合一般用途。
@Tino 这有帮助吗? ***.com/q/59777670/7389293看问题更新。【参考方案3】:
对于那些感兴趣的人,这是使用 sjcl
创建 SHA-256 哈希的代码:
import sjcl from 'sjcl'
const myString = 'Hello'
const myBitArray = sjcl.hash.sha256.hash(myString)
const myHash = sjcl.codec.hex.fromBits(myBitArray)
【讨论】:
对于那些想要在那里使用该解决方案的人来说,这应该包含在接受的答案中。 (哎呀,即使是他们自己的文档也没有这样的 sn-p) 这是最好的答案。我正在尝试加密解决方案,但它对我不起作用。【参考方案4】:Forge 的 SHA-256 实现快速且可靠。
要对多个 SHA-256 JavaScript 实现运行测试,请转至 http://brillout.github.io/test-javascript-hash-implementations/。
我机器上的结果表明,forge 是最快的实现,并且比公认答案中提到的斯坦福 Javascript 加密库 (sjcl) 快得多。
Forge 有 256 KB 大,但提取 SHA-256 相关代码会减小到 4.5 KB,请参阅 https://github.com/brillout/forge-sha256
【讨论】:
我设法用npm install node-forge
安装了它,但是现在,如何使用该库从字符串foo
创建一个哈希?【参考方案5】:
不,没有办法使用浏览器 JavaScript 来提高密码安全性。我强烈建议您阅读this article。就你而言,最大的问题是鸡蛋问题:
提供 Javascript 加密的“鸡蛋问题”是什么?
如果您不相信网络会传递密码,或者更糟糕的是,不相信服务器不会保守用户机密,那么您就无法相信它们会传递安全代码。在你引入加密之前嗅探密码或阅读日记的攻击者只是在你引入加密之后劫持加密代码。
[...]
为什么我不能使用 TLS/SSL 来传递 Javascript 加密代码?
你可以。这比听起来要难,但您可以使用 SSL 安全地将 Javascript 加密传输到浏览器。问题是,通过 SSL 建立了安全通道,您不再需要 Javascript 加密;你有“真正的”密码学。
这会导致:
在 Javascript 中运行加密代码的问题在于,实际上加密所依赖的任何函数都可能被用于构建托管页面的任何内容无声地覆盖。加密安全可以在过程早期撤消(通过生成虚假随机数,或通过篡改算法使用的常量和参数),或稍后(通过将密钥材料寄回给攻击者),或 --- 最有可能的情况——完全绕过加密货币。
对于任何一段 Javascript 代码都没有可靠的方法来验证其执行环境。 Javascript 加密代码不能问:“我真的是在处理随机数生成器,还是在处理攻击者提供的某个复制品?” 它当然不能断言“任何人都不得对这个加密秘密做任何事情,除非以我(作者)认可的方式”。这两个属性通常在其他环境中提供使用加密,它们在 Javascript 中是不可能的。
基本上问题是这样的:
您的客户不信任您的服务器,因此他们希望添加额外的安全代码。 该安全代码由您的服务器(他们不信任的服务器)提供。或者,
您的客户不信任 SSL,因此他们希望您使用额外的安全代码。 该安全代码通过 SSL 传递。注意:另外,SHA-256 不适合这种情况,因为brute force unsalted non-iterated passwords 很容易。如果您还是决定这样做,请寻找bcrypt、scrypt 或PBKDF2 的实现。
【讨论】:
这是不正确的。密码安全性可以通过在客户端进行散列来提高。只要在服务器端使用 PBKDF2 之类的东西,SHA-256 不适合也是错误的。第三,虽然 matasano 文章包含有用的见解,但妙语是错误的,因为我们现在拥有从根本上改变鸡与蛋问题的浏览器应用程序。 您说得对,应该在客户端使用 PBKDF2。对客户端 javascript 加密的愤怒假设初始页面和后续请求具有相同的安全属性。对于初始页面单独安装并且是静态的浏览器应用程序来说显然不是这样。对于任何具有永久缓存语义的页面来说,这也是不正确的。在这些情况下,与安装客户端程序时完全相同的是 TOFU。这也适用于更复杂的设置,其中静态和动态页面的服务在服务器上是分开的。 避免系统管理员访问用户密码是合法的,因此客户端的散列可以防止 DBA 或其他 IT 专业人员看到用户密码并尝试重用它来访问其他服务/系统,因为很多用户重复他们的密码。 @Xenland 您所做的只是创建一个新密码,即“令牌+密码”。所有原始问题仍然适用。例如,攻击者可以用代码替换 JavaScript 以向他们发送令牌 + 密码。 @Xenland 鸡和蛋的问题与您发送的请求没有任何关系。问题是您的客户端正在使用 它通过不安全的连接下载的 JavaScript 代码来执行安全工作。将 JavaScript 安全地发送到 Web 浏览器的唯一方法是通过 TLS 提供它,一旦你这样做了,你就不需要做任何其他事情,因为你的连接已经是安全的。如果您使用的是攻击者可以替换的 JavaScript 代码,那么您的协议是什么并不重要。【参考方案6】:我发现这个实现非常容易使用。也有一个慷慨的 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");
【讨论】:
【参考方案7】:除了 tylerl 提到的斯坦福库。我发现 jsrsasign 非常有用(这里的 Github 存储库:https://github.com/kjur/jsrsasign)。我不知道它的可信度如何,但我使用了它的 SHA256、Base64、RSA、x509 等 API,而且效果很好。事实上,它也包括斯坦福库。
如果您只想使用 SHA256,jsrsasign 可能有点矫枉过正。但如果你在相关领域有其他需求,我觉得还是很合适的。
【讨论】:
使用developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API更安全、更快捷 同意,但公平地说,我在 2015 年回答了这个问题,而 Mozilla 的网络加密 API 规范于 2017 年 1 月发布【参考方案8】:可以使用 CryptoJS - https://www.npmjs.com/package/crypto-js
import sha256 from 'crypto-js/sha256'
const hash = sha256('Text')
【讨论】:
【参考方案9】:ethers.js 有一个 SHA256 (https://docs.ethers.io/v5/api/utils/hashing/)
const ethers = require('ethers');
ethers.utils.sha256(ethers.utils.toUtf8Bytes('txt'));
【讨论】:
以上是关于是否有任何通常被认为值得信赖的 SHA-256 javascript 实现?的主要内容,如果未能解决你的问题,请参考以下文章
我在哪里可以找到 docker 镜像的 sha256 代码?
Python OPC UA 客户端安全策略(基本 256sha256)?
是否有内置的方法或插件让Jenkins为我的工件生成SHA256哈希?