关于 https 双向认证的细节

2021-05-02 18:12:35 +08:00
 angcz
最近看了下 https 双向认证,有些点没搞懂,还请大家指教一下。

1.客户端证书是怎么生成的?
看网上说是由颁发服务端证书的 ca 生成的,感觉应该不对吧?也许实际应用中是用服务端自签名证书生成的?

2.客户端证书是怎么安装到客户端的?
分 app 和网页两种情况;对于不同的用户,安装的 app 应该都是一样的吧,那就是说大家用的都是同一个客户端证书,感觉不对吧?而且如果是安装时内置的话,那网页要怎么办呢,网页没有安装的过程吧?所以应该是安装之后生成的?但是生成又需要 ca 私钥,这东西不可能内置在客户端,那是通过网络传给客户端的吗,这样没法保证安全,应该也不是的吧?

3.双向认证怎么防止抓包的呢?
以这里 https://cloud.tencent.com/developer/article/1171381 第五节的图为例,我如果抓包,只要把 4 和 6 透传给服务端,然后把 8 透传给客户端,不就能正常拦截到 9 (之前已经把服务端证书替换成抓包软件证书),也就拿到了对称加密密钥了吗?

再次感谢大家指导。
4768 次点击
所在节点    HTTP
43 条回复
angcz
2021-05-03 03:03:36 +08:00
你们要是真的觉得我有问题 你们有水平 就指出我的问题啊?一副自己很懂 我一文不值的样子 又不做任何详细的解释...这就是我为什么不想在网上发言 无论是讨论什么 只要大家不相识 不用在意面子 可以随便发言 就总会有人能让别人不舒服
musi
2021-05-03 08:03:19 +08:00
鉴于楼主第三点是关于单向和双向的问题,所以下面回答都分单双向讨论:
1.
单: 由权威 ca 生成证书,这里的权威 ca 一般指内置在操作系统里面的 ca 或已经被操作系统里面的 ca 信任过的 ca(可以是套娃)。
双: 一般由服务端自签生成,这时候你的服务器就充当了一个 ca 。
2. 单: 不需要安装证书,只要知道服务端生成的证书是已经被操作系统里的 ca 信任过的就行了。
双: 需要额外下载(网页需要用户手动操作安装,类似于微信商家,支付宝网银那一套。app 直接内置)
3. 你得了解 HTTPS 抓包的过程。
单: 首先在操作系统中信任一个代理服务器的证书,然后由这个代理服务器做中间人。对服务器端来说,代理服务器充当客户端,对客户端(浏览器或者 APP)来说充当服务器,客户端在校验域名合法性的时候发现操作系统根证书中包含代理服务器的证书于是通过,最后代理服务器拿到服务器的数据后自己再用 HTTPS 转发一次返回给客户端。
双: 由于服务器开启了 SSL Pinning,服务器只信任自己颁发的证书,所以在客户端安装第三方根证书,又中间人代理请求的方法就失效了,只有你说的 “之前已经把服务端证书替换成抓包软件证书” 我是不知道你怎么能做到替换服务端证书的,如果可以的话麻烦告知一下。
jadec0der
2021-05-03 08:21:23 +08:00
对双向 SSL 不熟悉,lz 知道第 8 步的 “加密方案” 是什么,包括一个随机数吗?看名字好像不包括的样子,客户端没有客户端私钥的话,可以猜到方案吗?
des
2021-05-03 09:06:24 +08:00
@angcz
1 、就目前实践来看,多数客户端证书生成,是由企业组织自行维护 pki 体系
2 、基于 1 来说,客户端证书基本都是基于可信通道传输,比如自己组织内网传输、用户后台下载然后短信接收压缩包密码,类似的方式。还有就是三楼所说的硬件内置。这种硬件一般都有防拆机制
3 、我说你不懂非对称加密也是基于条,请问使用公钥加密(你引用的文章第 9 条)你不拿到服务端私钥的情况下怎么解密?
4 、假设你替换了第四步的证书,那服务端验证根本不会通过,后续操作也不可能

5 、另外说一句这种都替换数据包了,通常我们不叫抓包,而是叫中间人。这个也是有些人产生误解的原因,然后你 append 又加深了误解
6 、现在常见的是 dh 密钥交换,根本不传输密码,即使你有私钥也解密不了数据
7 、客户端证书一个点,是可以确认客户端身份,仅对有证书的进行授权,可以针对性吊销证书
des
2021-05-03 09:22:01 +08:00
@des
补充刚刚的第 6 点,这里的指的是抓包数据,而非中间人
marcoxuu
2021-05-03 11:42:28 +08:00
@angcz 首先声明回复针对提问,并不针对提问者,回复中的赞同仅适用于 des 第一条回复的后半句,这里对第一次回复的表达不清晰道歉。
按照您回复中已有的基础,针对问题 1 和问题 2 中网页端的情况,请看 https://www.jianshu.com/p/d23b5ceefe12 这篇证书链开始到最后的部分;
问题 2 中 app 端的问题,eason1874 的回复已经说的很清楚。
问题 3 文中第四步准确的说应该是用服务端公钥加密客户端公钥,然后第五步时服务端私钥解密出客户端公钥并进行验证,所以第八步中中间人并不知道客户端的公钥,此时客户端公钥仅有服务端知道。
再假设即使客户端公钥被中间人知晓,第四步中中间人代替客户端发送的中间人公钥也会在第五步中服务端验证公钥过程中被服务端发现非信任客户端发来的公钥而拒绝服务。可以理解为此时客户端也相当于一个网站,拥有自己的域名证书,而这个证书是由相应的服务端签发的,但中间人的证书并不是服务端签发,所以中间人得不到信任,也就实现了所谓的双向认证过程。
参考链接:
https://en.wikipedia.org/wiki/Mutual_authentication 的 Defense 章节中提到:Mutual authentication can prevent MITM attacks because both the sender and recipient verify each other before sending them their message keys, so if one of the parties is not verified to be who they claim they are, the session will end.[9]
以上仅代表我的理解,如有差错敬请指导
holinhot
2021-05-03 15:50:52 +08:00
浏览器实现自动申请并安装客户端证书得用插件,至于 app.想怎么玩就怎么玩。
angcz
2021-05-03 19:07:42 +08:00
@musi

感谢回复

关于第 2 点,双向认证时,客户端证书是直接内置在 app 里的,对于不同的用户,app 内容应该是不变的吧?也就是说所有用户都是共享一个客户端证书?那样是不是会有很大的风险?还是说如同上面的回复,客户端证书其实是客户端安装后生成的,私钥保存在本地,通过向 ca 发送请求得到证书?

关于第 3 点,确实“之前已经把服务端证书替换成抓包软件证书”这句话我表达有问题,会让人产生误会,我指的其实是发给客户端的服务端证书实际上是抓包软件生成的证书。

我想了下,发现我之所以会有这样的疑问,应该是由于在网上看到了不同版本的抓包软件原理的图,其中第一种是如您所说,也就是这里( https://zhuanlan.zhihu.com/p/67199487 )的图;第二种是如这里( https://github.com/youngwind/blog/issues/108 )所说。这两者的区别是,客户端向服务端发送请求的过程,第一种说是被抓包软件拦截,然后抓包软件再向服务端发送请求;第二种是说抓包软件把这个请求透传给了服务端。我上面的疑问其实都是基于第二种展开的。
angcz
2021-05-03 19:45:21 +08:00
@des

感谢回复

关于第 1,2 点,您说的很清楚,其实我更关心的是移动端的情况下,客户端证书是怎么处理的,是否是如同上面所回复的,是客户端安装后生成,私钥保密,公钥发送给 ca,请求生成证书?如果是的话,那这个发送请求的过程,是怎么保证安全的?

关于第 3,4,5 点,我确实没有说清楚,其实我讨论的是我用抓包软件抓双向认证明文的情况,也就是说抓包软件作为中间人,介入了双向认证过程的情况。假设双向认证过程中,抓包软件只是拦截了服务端发送给客户端的证书,将其替换成自己动态生成的证书,其余信息都是透传的,并且客户端也信任了这个证书(假设客户端就算开启了 ssl pinning 但是被 hook 更改了)。那么第 3 点,之所以能解密,是因为假设抓包软件作为中间人,那么“服务端”私钥,其实就是中间人的私钥。第 4 点,因为没有替换证书,只是把客户端证书透传给了服务端,所以服务端也可以正常验证通过。关于第 5 点,确实,抓包软件的原理虽然是充当中间人,但是跟中间人不完全一样,所以我们可以简单地就视作现在是在考虑中间人攻击的情况。

关于第 6 点,假设用的是基于 dh 的 ecdhe,也就是说根据明文的四个参数无法算出密钥,而只要握手双方根据自己的私钥加明文参数,就可以算出对称加密密钥,因为客户端实际是将中间人当成服务端在交互,所以中间人用自己的私钥加公开参数,就可以算出对称加密密钥。

当然我上面的理解肯定存在错误,还请指正。
angcz
2021-05-03 19:49:35 +08:00
@eason1874 感谢回复,客户端证书是内置在 app 里,那么也就是说所有用户,都共享一个客户端证书?因为我理解不同用户下载的 app,内容应该是一样的?那样是不是会出现一个用户的客户端证书对应的私钥泄露后,所有用户都被波及的情况?
angcz
2021-05-03 20:15:54 +08:00
@marcoxuu

感谢回复

证书链的知识我有看过,我没有太明白这跟第 1,2 个问题的联系是?

如果如 eason 所说,客户端证书是内置在 app 里,那么也就是说所有用户,都共享一个客户端证书?因为我理解不同用户下载的 app,内容应该是一样的?那样是不是会出现一个用户的客户端证书对应的私钥泄露后,所有用户都被波及的情况?

如果如您所说,文中第四步是使用服务端公钥加密客户端公钥的话,那假设中间人是拦截了客户端 client hello,自己向服务端发送 client hello,然后接受了服务端证书,并将自己的证书返回给客户端,客户端信任了这个证书(假设客户端即使开启了 ssl pinning 也被 hook 关闭了),然后客户端用中间人公钥加密自己的证书,中间人收到加密后的证书,然后用自己的私钥解密,并用服务端的公钥加密,返回给服务端,服务端将加密方案用客户端公钥加密发送给中间人,中间人透传给客户端,客户端解密后用中间人公钥加密对称加密密钥参数,然后发送给中间人,中间人根据之前的参数和自己的私钥,不就可以算出对称加密密钥了吗?

当然我上面的理解肯定存在错误,还请指正。
musi
2021-05-03 20:34:44 +08:00
@angcz 第二点,其实是 SSL Pining 的选择问题,SSL PIning 提供证书锁定和公钥锁定,详情可以看这里 https://zhuanlan.zhihu.com/p/58204817
第三点,借着你的提问,我又去搜索了一下,直到我看到这篇 https://juejin.cn/post/6844903831579394055
双向认证和 SSL pining 并非一个东西,双向认证时客户端存了一个公钥证书和一个私钥,客户端用自己的证书加密数据,私钥用于解密服务器返回的数据其实这里是两套公钥证书+两套私钥,由于抓包软件并没有客户端的公钥证书所以服务端用私钥解密会失败,也就防止了抓包
angcz
2021-05-03 20:41:54 +08:00
@musi

感谢回复

不好意思 我没太懂你这里说的第二点是针对我的哪个回复的第二点 ssl pinning 的知识我有学习总结过,我可以在这里贴出来,但我没太明白这跟我的回复有什么关联。
( Certificate Pinning:我们需要将 APP 代码内置仅接受指定域名的证书,而不接受操作系统或浏览器内置的 CA 根证书对应的任何证书。但是 CA 签发证书都存在有效期问题,所以缺点是在证书续期后需要将证书重新内置到 APP 中。解决方法是可以提供预置证书更新接口。在当前证书快过期时,APP 请求获取新的预置证书,这过渡时期,两个证书同时有效,直到安全完成证书切换。这种方式有一定的维护成本,且不易测试。
Public Key Pinning:公钥锁定则是提取证书中的公钥并内置到移动端 APP 中,通过与服务器对比公钥值来验证连接的合法性,我们在制作证书密钥时,公钥在证书的续期前后都可以保持不变(即密钥对不变),所以可以避免证书有效期问题。但是,这样不太符合周期性更新私钥的安全审计需求。一个折中的方法是,一次性预置多个公钥,只要任意一个公钥验证通过即可。考虑到我们的证书一般购买周期是 3-5 年,那么 3 个公钥,可以使用 9-15 年,同时,我们在此期间还可以发布新版本废弃老公钥,添加新公钥,这样可以使公钥一直更新下去。 )

关于你说的第三点,双向认证和 ssl pinning 我清楚,也没有混淆,但是我还是没明白双向认证如何防止中间人攻击,可以看一下第 31 楼里倒数第二段的回复,我描述的这个流程,应该是有错误的,但是我没有想明白是哪个环节有问题,不好意思。
angcz
2021-05-03 20:49:00 +08:00
@ThirdFlame 假设使用的是 ecdhe 单向认证 抓包软件作为中间人与客户端交互 由于客户端实际是与抓包软件交互 所以抓包软件根据发送给客户端的中间人证书对应的私钥与之前交换的明文参数 不就可以算出对称加密密钥了吗?
musi
2021-05-03 20:54:08 +08:00
@angcz 其实你看我贴出来的第二篇文章就很容易理解了,客户端发出来的消息本身就是经过客户端的公钥加密的,中间人没有私钥又怎么去解密拦截呢?
eason1874
2021-05-03 21:06:54 +08:00
@angcz #30 对,默认情况下同一个 APP 版本用同一个客户端证书,如果泄露了,任何账号的请求都可以抓包。

双向认证已经可以排除只会用代理工具抓包的脚本小子了,APP 加固提高反编译难度也可以排除大部分破解了,加上一些用户行为分析基本够用。

更高级别的可以像支付宝数字证书那样一个用户设备一个证书,在多因素身份验证登录之后,给当前用户设备专门签发私有证书下发到 APP,接下来该用户就只用自己的证书进行通信,只有客户端证书也代理不了了。这也不是 100%理论安全的,照样可以通过 APP 目录文件破译找出证书,只是说难度又高了一点。如果真到那程度,不如双向认证配合自研协议,让抓到包也解不出来内容。

另外提一下你在#31 说的中间人介入协商,不可能成功的,这点你不用想了,在不可信网络建立可信连接是 SSL 的根基。协商过程中服务器会用客户端公钥加密协商方案发给客户端,收到数据要用客户端私钥才能解密,你没有客户端私钥是解不出来的,结果就是协商失败。
angcz
2021-05-03 21:18:00 +08:00
@musi “客户端发出来的消息本身就是经过客户端的公钥加密的” 第二个客户端是不是写错了,应该是服务端?如果是的话,抓包软件作为中间人介入密钥协商过程,这时客户端是在把中间人当作服务端进行交互,所以客户端是用中间人公钥进行加密,中间人有私钥,自然也可以解密。
eason1874
2021-05-03 21:39:58 +08:00
@angcz #37 不是你随便发个证书给服务器,服务器都会接受,必须是服务器信任 CA 签发的才会被接受。具体来说,客户端给服务器发客户端公钥证书,然后服务器用 CA 根证书从客户端公钥证书里解密出客户端公钥,你随便发一个是解不出来的。

在不可信网络中建立可信连接是 SSL 的根基,你知道你这个问题是在质疑被全世界密码学专家广泛接受的 SSL 的根基吗?别浪费时间了,没有意义的。

如果想学习可以去找文章或者教程看看,在这里讨论,大家就算懂,一时间也很难系统全面地阐述。
angcz
2021-05-03 21:53:23 +08:00
@eason1874 我知道你说的意思,我没有在质疑算法的合理性,相关的文章我也看了很多了,只是有些细节我没有想明白,我觉得是自己没理解对,但是现在想不出来是哪里没想对而已。
ThirdFlame
2021-05-04 09:55:53 +08:00
ssl 单向认证时 只需要客户端信赖中间人的证书 ,就能完成中间人攻击。 服务器无法区分客户端(此时对服务器而言客户端 就是 中间人)是否是有效的 受信任的。
ssl 双向认证时 你使用中间人攻击(没有客户端私钥、没有服务器端私钥)的情况 ,那么你不可能冒充客户端 跟 服务器进行通信。 如果你说那我把客户端私钥 给中间人, 那这就算不上中间人攻击了。

防止以下两种 1 、是指 中间人 冒充服务端跟客户端通信、同时冒充客户端跟服务端通信。2 、是指 仅通过对线路的侦听、抓包(此处抓包 不是指中间人)来进行数据窃取。

楼主已经混乱 在中间人 和 抓包中了。

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

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

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

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

© 2021 V2EX