怎么安全地在 web 前端存储私钥?

2021-07-03 23:13:52 +08:00
 JasonLaw

最近在看安全方面的知识,为了防止重放攻击,我查阅了一些资料。

also24 的回复说得非常棒。

单向的 https 只能保证你请求的银行真的是银行,但银行无法确定你是你。

加了 token 才能让银行知道你是你,但是银行不知道你带的东西是你自己带的,还是别人塞进你包里的。

加上 nonce 和签名,才能让银行知道这些东西全都是你带的,别人没有夹带,但是银行不知道这个你,是否是用 1 年前的你克隆出来的。

加上时间戳,银行才能确定面前的你确实是当前时间点真实存在你,东西也是你带的东西。

最后,稀奇古怪的加密又是什么呢? 答:你带的东西是一个保险箱~


但是我有一个疑问,产生签名是需要密钥的,那怎么安全地在 web 前端存储私钥呢?

8471 次点击
所在节点    程序员
46 条回复
janus77
2021-07-03 23:20:02 +08:00
浏览器的环境实现吧,浏览器这个软件本身是利用了操作系统的功能,和硬件做了交互。
JasonLaw
2021-07-03 23:25:00 +08:00
@janus77 #1 可以更加具体一点、使用外行人的语言描述吗?
xmumiffy
2021-07-03 23:36:03 +08:00
这种都是服务端间的交互方式,密钥直接写在代码里的。
要认证客户端可以使用双向证书
FaiChou
2021-07-03 23:38:29 +08:00
你是想在网页端做 ssl pinning ?

前端私钥怎么来的?服务器给的?服务器给的时候就可能被窃取。

安全存储了私钥,你得用代码获取它吧,你的代码能获取,怎么保证其他代码不能获取?

前端的东西都是透明的,不像 app 客户端可以封在包里,不过封在包里也可以被越狱 /root 来篡改。楼主想要的绝对安全的地方,不存在的。
hahasong
2021-07-03 23:40:48 +08:00
jwt 就行,已经标准化了
JasonLaw
2021-07-03 23:54:04 +08:00
@FaiChou #4 很多人都说“使用签名来保证来源的可靠性等等”,那它们是怎么处理私钥的?
JasonLaw
2021-07-03 23:56:05 +08:00
@hahasong #5 JWT 中的签名是由服务端存储的密钥产生的,跟我的提问有啥关系呢?
IvanLi127
2021-07-04 00:06:25 +08:00
我觉得每次都输入密码,用密码签名所有参数和时间戳,就能保证收到的东西就是你现在发送的。这个密码存可信的地方才行,你相信浏览器,那就能安全存储了。如果不相信自己,每次输入密码都没用
walpurgis
2021-07-04 00:16:12 +08:00
带签名的接口一般都是给服务端调用的,原帖没有任何地方提到前端
JasonLaw
2021-07-04 00:21:28 +08:00
@IvanLi127 #8 问题就是“怎么安全地在浏览器存储密码”😅
binux
2021-07-04 00:23:06 +08:00
浏览器安全是由浏览器保证的,你作为前端无论做什么都是没用的
JasonLaw
2021-07-04 00:25:49 +08:00
@walpurgis #9 是的,一般都是服务端请求服务端,原帖没有提到前端。但我的问题是关于浏览器端请求服务端。
SP00F
2021-07-04 00:29:14 +08:00
前端是防小人,不防君子。

都不信任,那就只能走一律不信的态度了
3dwelcome
2021-07-04 00:41:59 +08:00
"怎么安全地在 web 前端存储私钥?"
以前貌似我也在 V 站讨论过这问题,结论是普通加密保存就可以了。

但是有两点额外要素,第一是解密后私钥只确保使用一次后就失效。第二是每次用代码生成不一样的加密算法,就是前端存的不是私钥的解密密码,而是生成的解密代码虚拟机本身,比如 WEBASM 。
also24
2021-07-04 00:50:07 +08:00
感谢认可之前的回答,本身不是专门做安全的,可能还有很多纰漏。


具体到本帖的问题,我觉得不妨先定义一下『安全的存储』指的是什么。


首先,『安全的存储』可能是指:让这个私钥不出现在前端代码里。
那可以在用户的登录鉴权的接口中,增加一个字段返回,给每个用户自己专属的私钥。

按这个思路,为了复用这个私钥,需要将其存储在本地,可选 Cookie 或 localStorage 来存储。
此时『安全的存储』可能是指:让这个私钥不被本站之外的其它恶意站点获取。
- 使用 Cookie 方式存储时,正确设置 domain / path / secure 等字段。
- 使用 localStorage 方式存储时,默认只有同源页面可读写。

考虑到 Cookie 会被自动发送,相对来说更建议使用 localStorage 来存储私钥。


但是有些机智的朋友就说了,我打开 DevTools,不就直接看光光了么?
此时『安全的存储』可能是指:不让用户在 DevTools 中看到,或者手动运行 JS 代码获取到。

那就要请出第三方存储了,例如 U 盾等专门存储密钥的东东就是专门干这个的。
使用 U 盾还有一个好处,就是不需要登录鉴权就可以有私钥了,可以同时保护登录接口的安全。


那有些更机智的朋友肯定又想到了,那我直接破解你的 U 盾,导出你的私钥,不又看光光了么?
此时『安全的存储』就愈发变态了,还要考虑到硬件设备被破解的情况。
那可能就要搬出更极端的存储设备了 - 全靠大脑,直接硬背。


那有些搞催眠的朋友……………………
jadec0der
2021-07-04 02:12:58 +08:00
银行? U 盾啊
unco020511
2021-07-04 02:27:26 +08:00
---单向的 https 只能保证你请求的银行真的是银行,但银行无法确定你是你。
这句话很明显就是错误的,而且起码两处错误
1.什么叫单向 https?https 的过程是先由客户端和服务端通过[非对称加密]+[签名]机制协商出一套[对称加密秘钥],然后使用这套对称秘钥进行加密传输,双方数据都是使用对称加密传输的,何来单向一说?

2.只能保证你请求的是银行,但银行无法确定你是你?
1.https 非对称加密过程中,客户端会使用自己的私钥加密原文(的 hash)得到签名并发送,服务端会使用对应的公钥解密得到原文的 hash 并比对
2.同时也会校验 host 是不是客户端域名(或 ip),银行能确定你是你
3.如果说的是抓包 /控制台 F12,那与 https 安全性无关,属于你自己主动安装第三方证书
unco020511
2021-07-04 02:33:40 +08:00
如果你问的是 oath2,那前端怎么会存储私钥呢
xuanbg
2021-07-04 04:57:30 +08:00
所以银行会发你一个 usbKey 来存储证书啊。就是因为浏览器干不来这个事情,客户端任何常规存储方式都是不安全的。
JasonLaw
2021-07-04 07:27:18 +08:00
@also24 #15 👍 简单易懂

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/787379

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX