JavaScript有没有任何非对称加密选项?

25

我需要通过JavaScript AJAX调用在未加密的通道(HTTP,而非HTTPS)上传输一些敏感信息。

我想加密数据,但在JavaScript端进行加密意味着我会暴露密钥,这使得对称加密只是一种安全性混淆的练习。

是否有适用于JavaScript的非对称加密方法?这样,我就可以保持服务器解密密钥的机密性。(我不担心服务器> JavaScript消息的安全性,只关注某个JavaScript >服务器消息的安全性)

5个回答

17

你需要加密的原因可能是为了防止中间人攻击。在某些情况下,攻击者可以监听流量但无法修改它。这种解决方案将防止该威胁,但不提供任何保护来抵御能够修改流量的中间人攻击。

如果攻击者可以更改流量,那么他也将能够更改执行加密的脚本。最简单的攻击方式就是从脚本中完全删除加密。如果您没有使用 https,并且中间人攻击是可能的(几乎每种情况都是如此),则您对呈现给终端用户的 html 或 javascript 没有任何控制权。攻击者可以完全重写您的 html 代码和 javascript、禁用加密、在表单中创建新的表单字段等。在 web 渠道中进行安全通信的先决条件是使用 https。


同意,在JavaScript中进行加密是一个坏主意。此外,目前浏览器中没有任何安全的随机数生成JavaScript实现。这意味着在JavaScript中实现的任何密码学都将被破解,而不管其他威胁。 - molf
谢谢,这很有道理 - 我主要考虑嗅探,而不是操纵。我会再仔细考虑一下,看看是否可以使用HTTPS选项。 - Michael Stum
实际上,除非实现得非常小心,否则仅执行普通的不对称加密也不能防止窃听。通常你用RSA密钥加密对称密钥,然后使用对称会话密钥执行加密。该加密绑定使用带有某种填充的CBC。由于处理帖子的服务位于在线状态,因此您现在创建了一种容易受到填充预言机攻击的方案(密码学很有趣,不是吗?)。 - Maarten Bodewes
1
@sstendal:如果连接是https,我能在javascript中使用加密吗?我需要进行公钥加密。用户的表单字段由客户端上的私钥签名(客户端必须提供包含私钥的密钥库的位置)。然后发送到服务器。服务器通过使用相应的公钥验证签名来验证正确的用户是否签名。但我想这是不可能的。因为javascript是沙盒化的。我想你不能访问本地文件。如果我错了,请纠正我。有没有什么办法解决这个问题? - Ashwin
我们现在拥有子资源完整性 https://developer.mozilla.org/zh-CN/docs/Web/Security/Subresource_Integrity。这将保护被传送到浏览器的JavaScript。 - user2677034
虽然我同意一般的建议,但我强烈反对在JavaScript中使用加密通常是一个坏主意的说法。在软件中不存在百分之百的安全性。依赖单一机制(如https)来保护所有数据因此是错误的建议。Https并不能完全防止中间人攻击和嗅探。在JavaScript中使用加密作为额外的对策可以显著增加认证方案的难度。 - Andreas Vogl

14

我做到了。我使用这个JavaScript客户端的非对称RSA加密来防止登录凭证以明文形式通过HTTP发送。

目的是为了防止基于网络嗅探的登录请求重放攻击。当然,这并不像HTTPS那样安全,因为它不能抵御中间人攻击,但对于本地网络可能已经足够。

客户端加密使用Travis Tridwell的优秀作品,它基于JSBN。Travis的网页也可以生成私钥和公钥RSA密钥(如果您懒得使用openssl)。密钥以PKCS#1 PEM格式生成。我加密 username+password+timeInMs+timezone 以使加密内容在每次登录时更改。

在服务器端,我的Java代码使用Apache JMeter的org.apache.jmeter.protocol.oauth.sampler.PrivateKeyReader读取PKCS#1 PEM文件:

PrivateKey pk = (new PrivateKeyReader("myPrivateKeyFile.pem")).getPrivateKey();

然后我使用特定的方法解密加密内容:

byte[] enc = DatatypeConverter.parseBase64Binary(clientData);
Cipher rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.DECRYPT_MODE, pk);
byte[] dec = rsa.doFinal(enc);
String out = new String(dec, "UTF8");

然后我检查客户端的时间戳/时区是否与服务器端的时间戳/时区匹配。如果延迟小于几秒钟,登录过程将继续。否则,该请求被视为重放攻击,登录失败。


5
非对称公钥/私钥是唯一的方法来实现这一点。为了防止中间人攻击,服务器可以将公钥与用户密码哈希,然后用户(在浏览器中)重新计算哈希值 - 如果它们匹配,则用户可以确信来自服务器的公钥没有被篡改 - 这取决于只有服务器和用户知道用户的密码这一事实。
PS:我想将此写成评论,因为这比答案更合适,但我没有足够的积分 :)
请参见:openpgp.js以查看示例

你有没有关于如何使用公钥/私钥进行操作的资料? - nova

4

4

服务器与JavaScript消息是否通过HTTPS发送?

如果没有,那么中间人可以更改脚本。如果能够访问未加密数据的代码被破坏,任何加密都将无用。


1
我的问题说明它是HTTP,而不是HTTPS。这就是为什么我正在研究非对称加密的原因,以便我可以将解密密钥保留在服务器端。这正是非对称加密有助于解决的问题:中间人可以获取加密消息和用于加密的密钥,但如果没有解密密钥,那么这些信息就毫无用处。 - Michael Stum
5
中间人攻击也可以更改公钥。您还需要某种形式的身份验证,这在浏览器窗口中运行脚本的角度来看有些困难。 - Maarten Bodewes
1
@Erik:当然是非对称公钥。你说得没错,如果攻击者能够更改公钥,他/她也可以更改页面上的代码。因此,该方案只能防止窃听。只要Michael知道这个方案不能防御中间人攻击即可。 - Maarten Bodewes
1
@owl 仔细看,你说的是公钥。 - ErikE
2
@owl 我完全理解公钥/私钥加密 :) 请点击此链接并阅读“pubic”的定义。 - ErikE
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接