最近在看安全方面的知识,为了防止重放攻击,我查阅了一些资料。
also24 的回复说得非常棒。
单向的 https 只能保证你请求的银行真的是银行,但银行无法确定你是你。
加了 token 才能让银行知道你是你,但是银行不知道你带的东西是你自己带的,还是别人塞进你包里的。
加上 nonce 和签名,才能让银行知道这些东西全都是你带的,别人没有夹带,但是银行不知道这个你,是否是用 1 年前的你克隆出来的。
加上时间戳,银行才能确定面前的你确实是当前时间点真实存在你,东西也是你带的东西。
最后,稀奇古怪的加密又是什么呢? 答:你带的东西是一个保险箱~
但是我有一个疑问,产生签名是需要密钥的,那怎么安全地在 web 前端存储私钥呢?
1
janus77 2021-07-03 23:20:02 +08:00
浏览器的环境实现吧,浏览器这个软件本身是利用了操作系统的功能,和硬件做了交互。
|
3
xmumiffy 2021-07-03 23:36:03 +08:00 via Android
这种都是服务端间的交互方式,密钥直接写在代码里的。
要认证客户端可以使用双向证书 |
4
FaiChou 2021-07-03 23:38:29 +08:00 via iPhone 2
你是想在网页端做 ssl pinning ?
前端私钥怎么来的?服务器给的?服务器给的时候就可能被窃取。 安全存储了私钥,你得用代码获取它吧,你的代码能获取,怎么保证其他代码不能获取? 前端的东西都是透明的,不像 app 客户端可以封在包里,不过封在包里也可以被越狱 /root 来篡改。楼主想要的绝对安全的地方,不存在的。 |
5
hahasong 2021-07-03 23:40:48 +08:00
jwt 就行,已经标准化了
|
8
IvanLi127 2021-07-04 00:06:25 +08:00 via Android
我觉得每次都输入密码,用密码签名所有参数和时间戳,就能保证收到的东西就是你现在发送的。这个密码存可信的地方才行,你相信浏览器,那就能安全存储了。如果不相信自己,每次输入密码都没用
|
9
walpurgis 2021-07-04 00:16:12 +08:00
带签名的接口一般都是给服务端调用的,原帖没有任何地方提到前端
|
11
binux 2021-07-04 00:23:06 +08:00 via Android
浏览器安全是由浏览器保证的,你作为前端无论做什么都是没用的
|
12
JasonLaw OP @walpurgis #9 是的,一般都是服务端请求服务端,原帖没有提到前端。但我的问题是关于浏览器端请求服务端。
|
13
SP00F 2021-07-04 00:29:14 +08:00
前端是防小人,不防君子。
都不信任,那就只能走一律不信的态度了 |
14
3dwelcome 2021-07-04 00:41:59 +08:00
"怎么安全地在 web 前端存储私钥?"
以前貌似我也在 V 站讨论过这问题,结论是普通加密保存就可以了。 但是有两点额外要素,第一是解密后私钥只确保使用一次后就失效。第二是每次用代码生成不一样的加密算法,就是前端存的不是私钥的解密密码,而是生成的解密代码虚拟机本身,比如 WEBASM 。 |
15
also24 2021-07-04 00:50:07 +08:00 7
感谢认可之前的回答,本身不是专门做安全的,可能还有很多纰漏。
具体到本帖的问题,我觉得不妨先定义一下『安全的存储』指的是什么。 首先,『安全的存储』可能是指:让这个私钥不出现在前端代码里。 那可以在用户的登录鉴权的接口中,增加一个字段返回,给每个用户自己专属的私钥。 按这个思路,为了复用这个私钥,需要将其存储在本地,可选 Cookie 或 localStorage 来存储。 此时『安全的存储』可能是指:让这个私钥不被本站之外的其它恶意站点获取。 - 使用 Cookie 方式存储时,正确设置 domain / path / secure 等字段。 - 使用 localStorage 方式存储时,默认只有同源页面可读写。 考虑到 Cookie 会被自动发送,相对来说更建议使用 localStorage 来存储私钥。 但是有些机智的朋友就说了,我打开 DevTools,不就直接看光光了么? 此时『安全的存储』可能是指:不让用户在 DevTools 中看到,或者手动运行 JS 代码获取到。 那就要请出第三方存储了,例如 U 盾等专门存储密钥的东东就是专门干这个的。 使用 U 盾还有一个好处,就是不需要登录鉴权就可以有私钥了,可以同时保护登录接口的安全。 那有些更机智的朋友肯定又想到了,那我直接破解你的 U 盾,导出你的私钥,不又看光光了么? 此时『安全的存储』就愈发变态了,还要考虑到硬件设备被破解的情况。 那可能就要搬出更极端的存储设备了 - 全靠大脑,直接硬背。 那有些搞催眠的朋友…………………… |
16
jadec0der 2021-07-04 02:12:58 +08:00
银行? U 盾啊
|
17
unco020511 2021-07-04 02:27:26 +08:00
---单向的 https 只能保证你请求的银行真的是银行,但银行无法确定你是你。
这句话很明显就是错误的,而且起码两处错误 1.什么叫单向 https?https 的过程是先由客户端和服务端通过[非对称加密]+[签名]机制协商出一套[对称加密秘钥],然后使用这套对称秘钥进行加密传输,双方数据都是使用对称加密传输的,何来单向一说? 2.只能保证你请求的是银行,但银行无法确定你是你? 1.https 非对称加密过程中,客户端会使用自己的私钥加密原文(的 hash)得到签名并发送,服务端会使用对应的公钥解密得到原文的 hash 并比对 2.同时也会校验 host 是不是客户端域名(或 ip),银行能确定你是你 3.如果说的是抓包 /控制台 F12,那与 https 安全性无关,属于你自己主动安装第三方证书 |
18
unco020511 2021-07-04 02:33:40 +08:00
如果你问的是 oath2,那前端怎么会存储私钥呢
|
19
xuanbg 2021-07-04 04:57:30 +08:00 1
所以银行会发你一个 usbKey 来存储证书啊。就是因为浏览器干不来这个事情,客户端任何常规存储方式都是不安全的。
|
21
JasonLaw OP @unco020511 #17 “私钥加密,公钥解密”是什么东西?
|
22
FaiChou 2021-07-04 08:45:42 +08:00 via iPhone
@JasonLaw 你想了解的是:对称加密和非对称加密。去搜搜这相关的知识吧。元知识需要学的,不靠问。
|
23
mxT52CRuqR6o5 2021-07-04 09:23:14 +08:00 via Android
私钥不私的话破坏了很多假设,安全性就无法保证
|
24
ZeawinL 2021-07-04 10:06:12 +08:00 via Android
前端使用用户密码 hash 作为密钥?
|
25
evilStart 2021-07-04 10:29:52 +08:00 via Android
@FaiChou 该学习的是你吧。明明是公钥加密,私钥解密。要是能用公钥解密那这加密还有啥意义。
|
26
vibbow 2021-07-04 10:39:24 +08:00
U 盾就是干这个事情的呀
|
27
unco020511 2021-07-04 10:43:31 +08:00
@JasonLaw 非对称加密除了加密外,还有一个应用叫做数字签名,完整的非对称加密流程包括:对原文非对称加密+签名,也就是实际是将密文(公钥加密的)+签名(实际为 hash 后用私钥进行一次非对称加密运算得到)一起打包发送,这样做既保证了数据不会被中间方窃听,又保证了数据的完整性以及来源
|
28
JasonLaw OP @vibbow #26 前面已经有很多人说了这个了,如果没有其它想法的话,最好不要重复同样的东西。如果冒犯到你的话,我先说句抱歉,我只是不想让主题包含太多没意义的信息。
|
29
unco020511 2021-07-04 10:46:58 +08:00
@evilStart 25# 签名
|
30
BoringBB 2021-07-04 10:50:21 +08:00 via Android
使用客户端证书啊,在 ssl 握手的时候,服务器可以要求客户端提供证书来验证身份
|
31
geniussoft 2021-07-04 10:56:34 +08:00
|
32
also24 2021-07-04 10:57:02 +08:00
@unco020511 #17
看内容要参照上下文,不要直接臆测某句话的意思。 『单向的 https 』 指的是 https 只有『单向加密』么? 当然不是,参照上下文可以得出,此处指的是最常使用的,只有『单向认证』的 https,在后面的楼层中,我专门强调了 https 是支持『双向认证』的。 那『加密』和『认证』有什么区别呢? 加密只是用来保证数据在传输的过程中,其它人无法解码。 认证则是为了证明自己是自己。 在最常见的『单向认证』的 https 使用形式中,只对服务器端进行了『认证』。 客户端内置有可信根证书机构的证书信息,服务端持有根证书签发的中间证书签发的服务器证书(大部分场景下,还包含了相应的证书链信息),客户端通过验证服务端的证书,即可确认返回的信息是否确实来自对应的服务端。 也就是,让你确认『你请求的是银行』。 但是此时,银行能通过这个 https 连接信息确认『你是你』么?当然不能,因为每个人都可以这样发起连接。 想要确认『你是你』,就必须通过登录等其它手段来进行验证。 此时,如果引入『双向认证』,也就是客户端也持有一份证书,在 https 握手的时候发给服务端,服务端验证证书可信后才会放行。 在这个场景下,如果每个人持有的证书是独立的,就可以做到银行通过 https 的握手信息就能确认『你是你』。 最后小结: 1 、不要把『加密』和『认证』混淆了,二者虽然有联系,但不等同 2 、最常见的 https 使用方式都是『单向认证』,但不要忽视了『双向认证』的存在 |
33
xylophone21 2021-07-04 11:19:44 +08:00 1
说一下我的理解吧
1 、U Key 这种,额外的硬件。里面的私钥可以认为是读不出来的 2 、不能用 U Key,那么只能做一些假设 2.1 用户不会自己配合泄露私有,特别是配合很复杂时。比如打开浏览器的开发者页面做一顿骚操作,把手机借给黑客等。 2.2 黑客不能通过程序很容易的获取到,主要靠 OS 、浏览器保护。比如不能读别人的 localstorage,不允许跨域等 2.3 万一用户配合泄露了,不影响其他人 |
34
JasonLaw OP @unco020511 #27
你说“完整的非对称加密流程包括:对原文非对称加密+签名”,但是我看了 https://en.wikipedia.org/wiki/Public-key_cryptography,里面所说的是: With public-key cryptography, robust authentication is also possible. A sender can combine a message with a private key to create a short digital signature on the message. Anyone with the sender's corresponding public key can combine that message with a claimed digital signature; if the signature matches the message, the origin of the message is verified (i.e., it must have been made by the owner of the corresponding private key). 按照它所说的,非对称加密是非对称加密,签名是签名,并不是“包括”的关系。 --- 还有你说“签名是用私钥进行一次非对称加密运算得到”,我不同意加密这个说法,“签名是使用私钥产生的”会更加准确。 --- 我对安全方面并不是特别了解,如果有错误的地方,希望你能够指出。 |
35
unco020511 2021-07-04 12:20:32 +08:00
@JasonLaw #27 没错,你说的更准确,非对称加密不包括验签,我想表达的是非对称加密与验签往往成套出现.所以我用的是"非对称加密流程",而不是"非对称加密"
----你说的签名使用私钥产生这句话肯定是对的,因为"产生"这个词范围很大,我想表达是更具体一些的原理,非对称加密的算法有多种,但最终都是经过"复杂精密设计过的数学运算",有一个特点就是非对称加密和解密使用的是同一个"计算方式"(并不是逆运算,这与对称加密的算法有本质区别),所以加密和解密其实都是同样的数学运算,如果要抠字眼,那加密和解密其实不应该有严格区分. ---- “签名是用私钥进行一次非对称加密运算得到”,可以改成"签名是用私钥进行一次非对称运算(可能没有这个词,那就是数学运算)得到" ----- 我认为我俩表达的实际上完全是一个东西 |
37
unco020511 2021-07-04 12:28:37 +08:00
@also24 #32 抱歉,我是没有看到你原贴后面楼层的内容,只是看到楼主单独贴出的内容,所以就进行了讨论,误解了你的观点.
----- "银行确认是你"这个问题,你说的是业务方面[权限][用户]的身份确认,我说的是主机 a 与主机 b 通信中的身份确认,都没有错,只是没有对到一起 周末愉快 |
38
JasonLaw OP |
39
also24 2021-07-04 12:39:02 +08:00
@JasonLaw #34
@unco020511 #35 关于『签名』,我想要补充一下,其实『签名』这个词,也是可以产生误解的。 你们在讨论的『签名』,其实默认了在说『 RSA 签名』,是一种具体的签名机制。 原回复中的『签名』,其实是一个宽泛概念,只要能起到对内容验证的作用,就算签名,实际上,很多时候都在用更简单的方式来生成这种签名。 例如:md5( data + sk + nonce + ts) 这就是一种很常用的模式,它与 『 RSA 签名』毫无关联,但是从作用上来说,也可以被称作『签名』。 |
40
Lemeng 2021-07-04 14:42:17 +08:00
u 盾,多少年前就可以。现在估计企业的银行业务都还是靠 u 盾,不过普通人用的少了
|
41
Quarter 2021-07-04 15:25:12 +08:00 via iPhone
为啥私钥要在浏览器端存储啊,最多浏览器存存公钥就差不多了
|
42
Jooooooooo 2021-07-04 15:26:11 +08:00
先用对称加密交换密钥, 这个交换过程公网公开可见
然后再用这个密钥干活 |
43
FaiChou 2021-07-04 15:31:06 +08:00 via iPhone
@JasonLaw 36 楼。
我看了你的问题和对上面的回复,感觉是对加密算法这些概念不是很清楚,所以让你先去学习下,我并没有什么好分享的,要分享也只是搬运网上的知识点过来,所以还是指出知识点让你自己去看更好。看了楼下的讨论,或许讨论多了你更能知道自己的疑问所在。可能最后一句冲突到了你,抱歉。 关于加密算法这里面有个简易的教程: http://blog.cnbang.net/tech/3386/ 希望能帮到你。 @evilStart 谢谢指出问题,4 楼我的回复有错。 |
45
wooyuntest 2021-07-04 17:07:25 +08:00
此处的签名 指的不是非对称加密算法(如 RSA 、ECC 等)算法中的签名、此处的签名指的只是对浏览器发出的 http 报文用前后端约定好的算法生成一个 sign 字段附在报文中,后段程序接到请求后,使用同样的算法再次计算 sign 并与你发送的报文中的 sign 字段比对,若 sign==sign 则认为报文没有经过篡改(在 App 没有被逆向得到加密算法的情况下),也就是你说的“才能让银行知道这些东西全都是你带的,别人没有夹带”。 这种做法常常用在 App 中来防止用户抓包修改报文以实现一些爬虫、辅助功能或用来测试后段的安全性。(因为在拿不到签名算法的情况下,用户篡改的报文在 ckecksign 阶段就被拒绝了),在基于浏览器的 web 应用中不会有这种做法,如果在浏览器中使用这种做法,会直接将加密算法公开,使得这种验签来判断报文没有经过修改的方式失去意义。
//但是这种做法银行还是没有办法确认你就是你,判断你访问的银行就是真正的银行,是基于 PKI 体系来实现的。所以目前银行用来判断你就是你,用的方法也类似。在硬件设备(也就是常说的 U 盾)中创建非对称密钥对,导出公钥并与你关联,私有永久保存在 u 盾中,认证的时候,有一个密码学常见的 challenge-response 过程来实现。(可以思考下 ssh 密钥对登陆的密码学原理) //可以看下 webauthn 的介绍和文档,他实现了 passless,也是未来 web 认证的趋势。会有不少新的收获。 //ps 在配备有 Touch ID 的 Mac 上用 Safari 登陆 iCloud 的时候,只用验证指纹,思考下这个是如何实现的? |
46
Nyarime 2021-07-04 22:38:40 +08:00
https://secure.quantumca.com.cn QuantumCA 的前端(下简称“Secure Center”)颁发 SSL 证书平台采用了 WebCrypto + WebAssembly 的前端私钥方案
具体策略如下: 1. 浏览器 JS 调用 WebCrypto 来生成 CSR + KEY ( RSA 或 ECC ), 2. 用户提交 SSL 订单,发送 CSR 和用户的域名信息到 Quantum 服务器, 3. Quantum 服务器提交到 CA, 4. CA 签发 SSL 证书,回调给 Quantum, 5. Secure Center 利用接口返回的 SSL 和浏览器本地( localStorage )的私钥,用 WebAssembly + Go 转换出 IIS 的 PFX 格式证书,和 Java 的 JKS 证书,并打包压缩 ZIP,生成 Blob 对象绑定到下载按钮上。 以上是我们采用的高性能的,解决信任问题的证书签发下发系统。 参考文献: 1. <Go WebAssembly 尝试&瘦身> - 2020/09/16 https://yryz.net/post/go-wasm/ |