我正在为一个论坛编写一个登录名,并且需要在将其发送到服务器之前在javascript中对密码客户端进行哈希处理。我无法确定哪些SHA-256实现我可以信任。我期待每个人都使用某种权威的脚本,但我发现大量不同的项目都有自己的实现。
我意识到使用其他人的加密始终是信仰的飞跃,除非你有资格自己审查它,并且没有“值得信赖”的普遍定义,但这似乎是一种常见且重要的东西,应该是在使用什么方面达成某种共识。我只是天真吗?
编辑因为它在评论中出现了很多:是的,我们在服务器端再次执行更严格的哈希。客户端散列不是我们在数据库中保存的最终结果。客户端散列是因为人类客户端请求它。他们没有给出具体原因,可能他们只是喜欢矫枉过正。
答案 0 :(得分:83)
Stanford JS Crypto Library包含SHA-256的实现。虽然JS中的加密并不像其他实现平台那样经过良好的审查,但这个问题至少部分由Dan Boneh赞助,并且在某种程度上由NSF赞助,他是一个成熟且值得信赖的人。密码学中的名称,意味着该项目对实际知道他在做什么的人有一些疏忽。该项目也得到add your own improvements的支持。
值得指出的是,然而......
...如果您在提交密码之前对客户端密码进行哈希处理,那么哈希就是密码,原始密码就变得无关紧要了。攻击者只需截取哈希以模仿用户,如果该哈希未经修改地存储在服务器上,那么服务器就会在平原中存储 true 密码(哈希) -text 强>
所以您的安全性现在更糟,因为您决定{{3}}以前是一个受信任的计划。
答案 1 :(得分:18)
在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;
}
请注意crypto.subtle
仅适用于https
或localhost
- 例如,对于python3 -m http.server
的本地开发,您需要将此行添加到/etc/hosts
}:
0.0.0.0 localhost
重新启动 - 您可以使用localhost:8000
打开crypto.subtle
。
答案 2 :(得分:14)
Forge的SHA-256实施快速可靠。
要在多个SHA-256 JavaScript实现上运行测试,请转到http://brillout.github.io/test-javascript-hash-implementations/。
我的机器上的结果表明伪造是最快的实现,也比接受的答案中提到的Stanford Javascript Crypto Library(sjcl)快得多。
Forge大256 KB,但提取SHA-256相关代码会将大小减小到4.5 KB,请参阅https://github.com/brillout/forge-sha256
答案 3 :(得分:10)
不,没有办法使用浏览器JavaScript来提高密码安全性。我强烈建议您阅读this article。在你的情况下,最大的问题是鸡蛋问题:
提供Javascript加密技术的“鸡蛋问题”是什么?
如果您不信任网络提供密码,或者更糟糕的是,不信任服务器不保留用户机密,则您不能相信它们提供安全代码。在你引入加密之前嗅探密码或阅读日记的同一个攻击者只是劫持了加密代码。
[...]
为什么我不能使用TLS / SSL来传递Javascript加密代码?
你可以。它比听起来更难,但你可以安全地使用SSL将Javascript加密传输到浏览器。问题是,通过SSL建立安全通道后,您不再需要Javascript加密;你有“真正的”密码学。
导致这一点:
在Javascript中运行加密代码的问题在于,几乎任何加密所依赖的函数都可以被用于构建托管页面的任何内容静默覆盖。加密安全性可以在过程的早期(通过生成伪随机数,或通过篡改算法使用的常量和参数)或稍后(通过将关键材料激活回攻击者)或 - 中撤消。最可能的情况---完全绕过加密。
任何一段Javascript代码都没有可靠的方法来验证其执行环境。 Javascript加密代码不能问,“我真的在处理一个随机数生成器,还是一些攻击者提供的传真?” 它当然不能断言“除了我作者批准的方式之外,没有人被允许对这个加密秘密做任何事情。”这些是通常在其他环境中提供的两个属性使用加密,在Javascript中它们是不可能的。
基本上问题是:
或者,
注意:此外,SHA-256不适用于此,因为brute force unsalted non-iterated passwords很容易。如果您仍然决定执行此操作,请查找bcrypt,scrypt或PBKDF2的实施。
答案 4 :(得分: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");
答案 5 :(得分:5)
对于那些感兴趣的人,这是使用sjcl
创建SHA-256哈希的代码:
import sjcl from 'sjcl'
const myString = 'Hello'
const myBitArray = sjcl.hash.sha256.hash(myString)
const myHash = sjcl.codec.hex.fromBits(myBitArray)
答案 6 :(得分:0)
除了tylerl提到的斯坦福lib。我发现jsrsasign非常有用(Github repo here:https://github.com/kjur/jsrsasign)。我不知道它是多么值得信赖,但我已经使用了它的SHA256,Base64,RSA,x509等API,它运行得很好。事实上,它也包括斯坦福大学的lib。
如果你想要做的只是SHA256,那么jsrsasign可能是一种矫枉过正。但如果你在相关领域有其他需求,我觉得它很合适。