怎么安全地在 web 前端存储私钥? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
JasonLaw
V2EX    程序员

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

  •  
  •   JasonLaw 2021-07-03 23:13:52 +08:00 9638 次点击
    这是一个创建于 1565 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    also24 的回复说得非常棒。

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

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

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

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

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


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

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

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

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

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

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

    但是有两点额外要素,第一是解密后私钥只确保使用一次后就失效。第二是每次用代码生成不一样的加密算法,就是前端存的不是私钥的解密密码,而是生成的解密代码虚拟机本身,比如 WEBASM 。
    also24
        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 盾,导出你的私钥,不又看光光了么?
    此时『安全的存储』就愈发变态了,还要考虑到硬件设备被破解的情况。
    那可能就要搬出更极端的存储设备了 - 全靠大脑,直接硬背。


    那有些搞催眠的朋友……………………
    jadec0der
        16
    jadec0der  
       2021-07-04 02:12:58 +08:00
    银行? U 盾啊
    unco020511
        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 安全性无关,属于你自己主动安装第三方证书
    unco020511
        18
    unco020511  
       2021-07-04 02:33:40 +08:00
    如果你问的是 oath2,那前端怎么会存储私钥呢
    xuanbg
        19
    xuanbg  
       2021-07-04 04:57:30 +08:00   1
    所以银行会发你一个 usbKey 来存储证书啊。就是因为浏览器干不来这个事情,客户端任何常规存储方式都是不安全的。
    JasonLaw
        20
    JasonLaw  
    OP
      &nsp;2021-07-04 07:27:18 +08:00 via iPhone
    @also24 #15 简单易懂
    JasonLaw
        21
    JasonLaw  
    OP
       2021-07-04 07:30:29 +08:00 via iPhone
    @unco020511 #17 “私钥加密,公钥解密”是什么东西?
    ethusdt
        22
    ethusdt  
       2021-07-04 08:45:42 +08:00 via iPhone
    @JasonLaw 你想了解的是:对称加密和非对称加密。去搜搜这相关的知识吧。元知识需要学的,不靠问。
    mxT52CRuqR6o5
        23
    mxT52CRuqR6o5  
       2021-07-04 09:23:14 +08:00 via Android
    私钥不私的话破坏了很多假设,安全性就无法保证
    ZeawinL
        24
    ZeawinL  
       2021-07-04 10:06:12 +08:00 via Android
    前端使用用户密码 hash 作为密钥?
    evilStart
        25
    evilStart  
       2021-07-04 10:29:52 +08:00 via Android
    @FaiChou 该学习的是你吧。明明是公钥加密,私钥解密。要是能用公钥解密那这加密还有啥意义。
    vibbow
        26
    vibbow  
       2021-07-04 10:39:24 +08:00
    U 盾就是干这个事情的呀
    unco020511
        27
    unco020511  
       2021-07-04 10:43:31 +08:00
    @JasonLaw 非对称加密除了加密外,还有一个应用叫做数字签名,完整的非对称加密流程包括:对原文非对称加密+签名,也就是实际是将密文(公钥加密的)+签名(实际为 hash 后用私钥进行一次非对称加密运算得到)一起打包发送,这样做既保证了数据不会被中间方窃听,又保证了数据的完整性以及来源
    JasonLaw
        28
    JasonLaw  
    OP
       2021-07-04 10:43:36 +08:00 via iPhone
    @vibbow #26 前面已经有很多人说了这个了,如果没有其它想法的话,最好不要重复同样的东西。如果冒犯到你的话,我先说句抱歉,我只是不想让主题包含太多没意义的信息。
    unco020511
        29
    unco020511  
       2021-07-04 10:46:58 +08:00
    @evilStart 25# 签名
    BoringBB
        30
    BoringBB  
       2021-07-04 10:50:21 +08:00 via Android
    使用客户端证书啊,在 ssl 握手的时候,服务器可以要求客户端提供证书来验证身份
    geniussoft
        31
    geniussoft  
       2021-07-04 10:56:34 +08:00
    @also24 啥? U 蹲被破解?

    以后开通网上银行,要求用户默背 2048 位密钥,并且熟练掌握口算非对称加密,绝对不能动笔
    also24
        32
    also24  
       2021-07-04 10:57:02 +08:00
    @unco020511 #17
    看内容要参照上下文,不要直接臆测某句话的意思。

    『单向的 https 』 指的是 https 只有『单向加密』么?
    当然不是,参照上下文可以得出,此处指的是最常使用的,只有『单向认证』的 https,在后面的楼层中,我专门强调了 https 是支持『双向认证』的。

    那『加密』和『认证』有什么区别呢?
    加密只是用来保证数据在传输的过程中,其它人无法解码。
    认证则是为了证明自己是自己。

    在最常见的『单向认证』的 https 使用形式中,只对服务器端进行了『认证』。
    客户端内置有可信根证书机构的证书信息,服务端持有根证书签发的中间证书签发的服务器证书(大部分场景下,还包含了相应的证书链信息),客户端通过验证服务端的证书,即可确认返回的信息是否确实来自对应的服务端。

    也就是,让你确认『你请求的是银行』。

    但是此时,银行能通过这个 https 连接信息确认『你是你』么?当然不能,因为每个人都可以这样发起连接。
    想要确认『你是你』,就必须通过登录等其它手段来进行验证。

    此时,如果引入『双向认证』,也就是客户端也持有一份证书,在 https 握手的时候发给服务端,服务端验证证书可信后才会放行。
    在这个场景下,如果每个人持有的证书是独立的,就可以做到银行通过 https 的握手信息就能确认『你是你』。


    最后小结:
    1 、不要把『加密』和『认证』混淆了,二者虽然有联系,但不等同
    2 、最常见的 https 使用方式都是『单向认证』,但不要忽视了『双向认证』的存在
    xylophone21
        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 万一用户配合泄露了,不影响其他人
    JasonLaw
        34
    JasonLaw  
    OP
       2021-07-04 11:57:56 +08:00
    @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).

    按照它所说的,非对称加密是非对称加密,签名是签名,并不是“包括”的关系。

    ---

    还有你说“签名是用私钥进行一次非对称加密运算得到”,我不同意加密这个说法,“签名是使用私钥产生的”会更加准确。

    ---

    我对安全方面并不是特别了解,如果有错误的地方,希望你能够指出。
    unco020511
        35
    unco020511  
       2021-07-04 12:20:32 +08:00
    @JasonLaw #27 没错,你说的更准确,非对称加密不包括验签,我想表达的是非对称加密与验签往往成套出现.所以我用的是"非对称加密流程",而不是"非对称加密"
    ----你说的签名使用私钥产生这句话肯定是对的,因为"产生"这个词范围很大,我想表达是更具体一些的原理,非对称加密的算法有多种,但最终都是经过"复杂精密设计过的数学运算",有一个特点就是非对称加密和解密使用的是同一个"计算方式"(并不是逆运算,这与对称加密的算法有本质区别),所以加密和解密其实都是同样的数学运算,如果要抠字眼,那加密和解密其实不应该有严格区分.
    ----
    “签名是用私钥进行一次非对称加密运算得到”,可以改成"签名是用私钥进行一次非对称运算(可能没有这个词,那就是数学运算)得到"
    -----
    我认为我俩表达的实际上完全是一个东西
    JasonLaw
        36
    JasonLaw  
    OP
       2021-07-04 12:24:12 +08:00
    @FaiChou #22 你的这个回复是回复哪个的?如果你愿意的话,可以指出我的错误,而不是不愿意分享的样子。
    unco020511
        37
    unco020511  
       2021-07-04 12:28:37 +08:00
    @also24 #32 抱歉,我是没有看到你原贴后面楼层的内容,只是看到楼主单独贴出的内容,所以就进行了讨论,误解了你的观点.
    -----
    "银行确认是你"这个问题,你说的是业务方面[权限][用户]的身份确认,我说的是主机 a 与主机 b 通信中的身份确认,都没有错,只是没有对到一起

    周末愉快
    JasonLaw
        38
    JasonLaw  
    OP
       2021-07-04 12:34:48 +08:00
    @unco020511 #37
    @also24 #32

    我的错
    also24
        39
    also24  
       2021-07-04 12:39:02 +08:00
    @JasonLaw #34
    @unco020511 #35
    关于『签名』,我想要补充一下,其实『签名』这个词,也是可以产生误解的。

    你们在讨论的『签名』,其实默认了在说『 RSA 签名』,是一种具体的签名机制。

    原回复中的『签名』,其实是一个宽泛概念,只要能起到对内容验证的作用,就算签名,实际上,很多时候都在用更简单的方式来生成这种签名。

    例如:md5( data + sk + nonce + ts)
    这就是一种很常用的模式,它与 『 RSA 签名』毫无关联,但是从作用上来说,也可以被称作『签名』。
    Lemeng
        40
    Lemeng  
       2021-07-04 14:42:17 +08:00
    u 盾,多少年前就可以。现在估计企业的银行业务都还是靠 u 盾,不过普通人用的少了
    Quarter
        41
    Quarter  
       2021-07-04 15:25:12 +08:00 via iPhone
    为啥私钥要在浏览器端存储啊,最多浏览器存存公钥就差不多了
    Jooooooooo
        42
    Jooooooooo  
       2021-07-04 15:26:11 +08:00
    先用对称加密交换密钥, 这个交换过程公网公开可见

    然后再用这个密钥干活
    ethusdt
        43
    ethusdt  
       2021-07-04 15:31:06 +08:00 via iPhone
    @JasonLaw 36 楼。

    我看了你的问题和对上面的回复,感觉是对加密算法这些概念不是很清楚,所以让你先去学习下,我并没有什么好分享的,要分享也只是搬运网上的知识点过来,所以还是指出知识点让你自己去看更好。看了楼下的讨论,或许讨论多了你更能知道自己的疑问所在。可能最后一句冲突到了你,抱歉。
    关于加密算法这里面有个简易的教程: http://blog.cnbang.net/tech/3386/

    希望能帮到你。



    @evilStart 谢谢指出问题,4 楼我的回复有错。
    wzwb
        44
    wzwb  
       2021-07-04 16:50:57 +08:00 via Android
    wooyuntest
        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 的时候,只用验证指纹,思考下这个是如何实现的?
    Nyarime
        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/
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     4631 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 32ms UTC 04:02 PVG 12:02 LAX 21:02 JFK 00:02
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86