本周,CloudFlare宣布,开始提供Keyless服务,即你把网站放到它们的CDN上,不用提供自己的私钥,也能使用SSL加密链接。
我看了CloudFlare的说明(这里和这里),突然意识到这是绝好的例子,可以用来说明SSL/TLS协议的运行机制。它配有插图,很容易看懂。
下面,我就用这些图片作为例子,配合我半年前写的《SSL/TLS协议运行机制的概述》,来解释SSL协议。
一、SSL协议的握手过程
开始加密通信之前,客户端和服务器首先必须建立连接和交换参数,这个过程叫做握手(handshake)。
假定客户端叫做爱丽丝,服务器叫做鲍勃,整个握手过程可以用下图说明(点击看大图)。
握手阶段分成五步。
第一步,爱丽丝给出协议版本号、一个客户端生成的随机数(Client random),以及客户端支持的加密方法。
第二步,鲍勃确认双方使用的加密方法,并给出数字证书、以及一个服务器生成的随机数(Server random)。
第三步,爱丽丝确认数字证书有效,然后生成一个新的随机数(Premaster secret),并使用数字证书中的公钥,加密这个随机数,发给鲍勃。
第四步,鲍勃使用自己的私钥,获取爱丽丝发来的随机数(即Premaster secret)。
第五步,爱丽丝和鲍勃根据约定的加密方法,使用前面的三个随机数,生成"对话密钥"(session key),用来加密接下来的整个对话过程。
上面的五步,画成一张图,就是下面这样。
二、私钥的作用
握手阶段有三点需要注意。
(1)生成对话密钥一共需要三个随机数。
(2)握手之后的对话使用"对话密钥"加密(对称加密),服务器的公钥和私钥只用于加密和解密"对话密钥"(非对称加密),无其他作用。
(3)服务器公钥放在服务器的数字证书之中。
从上面第二点可知,整个对话过程中(握手阶段和其后的对话),服务器的公钥和私钥只需要用到一次。这就是CloudFlare能够提供Keyless服务的根本原因。
某些客户(比如银行)想要使用外部CDN,加快自家网站的访问速度,但是出于安全考虑,不能把私钥交给CDN服务商。这时,完全可以把私钥留在自家服务器,只用来解密对话密钥,其他步骤都让CDN服务商去完成。
上图中,银行的服务器只参与第四步,后面的对话都不再会用到私钥了。
三、DH算法的握手阶段
整个握手阶段都不加密(也没法加密),都是明文的。因此,如果有人窃听通信,他可以知道双方选择的加密方法,以及三个随机数中的两个。整个通话的安全,只取决于第三个随机数(Premaster secret)能不能被破解。
虽然理论上,只要服务器的公钥足够长(比如2048位),那么Premaster secret可以保证不被破解。但是为了足够安全,我们可以考虑把握手阶段的算法从默认的RSA算法,改为 Diffie-Hellman算法(简称DH算法)。
采用DH算法后,Premaster secret不需要传递,双方只要交换各自的参数,就可以算出这个随机数。
上图中,第三步和第四步由传递Premaster secret变成了传递DH算法所需的参数,然后双方各自算出Premaster secret。这样就提高了安全性。
四、session的恢复
握手阶段用来建立SSL连接。如果出于某种原因,对话中断,就需要重新握手。
这时有两种方法可以恢复原来的session:一种叫做session ID,另一种叫做session ticket。
session ID的思想很简单,就是每一次对话都有一个编号(session ID)。如果对话中断,下次重连的时候,只要客户端给出这个编号,且服务器有这个编号的记录,双方就可以重新使用已有的"对话密钥",而不必重新生成一把。
上图中,客户端给出session ID,服务器确认该编号存在,双方就不再进行握手阶段剩余的步骤,而直接用已有的对话密钥进行加密通信。
session ID是目前所有浏览器都支持的方法,但是它的缺点在于session ID往往只保留在一台服务器上。所以,如果客户端的请求发到另一台服务器,就无法恢复对话。session ticket就是为了解决这个问题而诞生的,目前只有Firefox和Chrome浏览器支持。
上图中,客户端不再发送session ID,而是发送一个服务器在上一次对话中发送过来的session ticket。这个session ticket是加密的,只有服务器才能解密,其中包括本次对话的主要信息,比如对话密钥和加密方法。当服务器收到session ticket以后,解密后就不必重新生成对话密钥了。
(完)
瑞意 说:
阮兄,深入浅出的讲解,很好理解了
2014年9月20日 18:58 | # | 引用
c 说:
我看了 CloudFlare 的说明(这里和这里)
两个这里是同一个链接
2014年9月21日 16:31 | # | 引用
阮一峰 说:
@c:
谢谢指出,已经改过来了。
2014年9月21日 18:53 | # | 引用
xzy 说:
这段话比较牵强了,有不同方案的集群session保存方案.
2014年9月22日 10:28 | # | 引用
qianqian 说:
个人理解,这应该算是CloudFlare产品创新,相当于他能提供一个PKI正常验证体系下的证书颁发机构,这个机构可以用来为开启KeyLess服务的站颁发证书
2014年9月22日 15:13 | # | 引用
qalong 说:
同意,现在大型应用基本上都是集群环境,session很少保存在一台服务器上。很多都是用集中式session管理
2014年9月22日 15:57 | # | 引用
林晨 说:
深入浅出,受教。
2014年9月23日 09:17 | # | 引用
zjhiphop 说:
阮哥的每篇文章都是必看的!!
2014年9月23日 10:28 | # | 引用
ciciywg 说:
安全系列的科普文章写的真是不错,图文并茂,深入浅出,赞!
2014年9月23日 10:39 | # | 引用
hilyb 说:
不错的文章。感觉使用SSL好烦人,证书生成什么的烦死了。
2014年9月23日 17:34 | # | 引用
xiongxiong 说:
恩,我也想知道cloudflare怎么解决证书的网站签名问题。
2014年9月25日 10:07 | # | 引用
铜矿 说:
阮兄的页面对手机浏览器支持不太好,现在很多人会用手机阅读,建议针对移动浏览器做一些优化
2014年9月26日 15:26 | # | 引用
爱国者 说:
DH算法虽然无需从客户端发送pre-master key, 但server DH参数和client DH参数应该是明文发送的吧,加上前面两个随机数也是明文发送的,那第三者完全能通过抓包的办法拿到server DH,client DH以及前两个随机数,然后自己生成会话密钥。这样后续的加密通信岂不是不安全?
2014年10月 7日 11:25 | # | 引用
xoxo 说:
HTTPS服务器的底层SESSION内存 很难集群。
2014年10月13日 14:18 | # | 引用
杨历 说:
作者说的是rfc5077,是传输层TLS通信的Session。不是应用层HTTP的Session。
2014年10月22日 21:23 | # | 引用
小胜 说:
这里DH算法有说,有限域内计算离散对数是几乎不可能的任务;得到这些参数是比较难算出密钥的;另外,我觉得这篇文章只说明了SSL协议使用DH算法的情况吧,在试用RSA等其他算法的时候,是不是不用再生成密钥对?服务器直接把公钥传给客户端就直接传输数据了?求解惑!
2014年11月 2日 15:17 | # | 引用
pimgeek 说:
我也有同样的困惑。后面小胜的回答,虽然听起来很专业,信度很高,但是他没有因循作者的讲解思路。
作者阮一峰的讲解思路是说采用 DH 算法,可以绕开Premaster secret被强行破解的风险:
而小胜的回答思路是:是说采用 DH 算法,在理论上也能保证Premaster secret不被破解,而且并没说明从理论上看【原始算法】和【DH算法】哪个更容易被强行破解。
2014年11月30日 00:38 | # | 引用
贾岛 说:
是的,session ticket是保存在客户端的,无需在服务端保存,因为session ticket就是对话密钥和加密方法经过加密后的信息。
2014年12月 5日 16:46 | # | 引用
不经夸 说:
是分布式缓存吧 加上session容易丢失 使用分布式缓存是非常好的 也解决了只能在一台机子上的问题
2014年12月 8日 10:55 | # | 引用
ranger_ray 说:
这是DH算法的一个简单描述:
1) A随机产生一个大整数a,然后计算Ka=ga mod n。(a需要保密)
2) B随机产生一个大整数b,然后计算Kb=gb mod n。(b需要保密)
3) A把Ka发送给B,B把Kb发送给A
4) A计算K=Kba mod n
5) B计算K=Kab mod n
由于Kba mod n= (gb mod n)a mod n= (ga mod n)b mod n,因此可以保证双方得到的K是相同的,K即是共享的密钥。
意思是说client与server端都有一个随机数是不会通过网络传输的。所以保证了安全。
(所以感觉说明DH原理的那张图,不是很贴切,不知道自己理解对不)
2014年12月13日 23:15 | # | 引用
aya 说:
如果服务器对客户端认证,而客户端不用对服务器认证,那么握手的过程应该什么样的呢?
2015年1月 8日 13:20 | # | 引用
WT 说:
真的好难啊,和以前的学的东西混在一起,彻底晕了!
2015年1月24日 14:32 | # | 引用
gg 说:
这几张图的确说明的超级详细容易理解~ DH那里原图没有具体说明不容易被破解的原因,现在实际使用起来配合其他工具的确保密性更高。话说,看完整篇文章,只看到SSL了,没看到TLS。。。
2015年4月10日 10:00 | # | 引用
御剑飞星 说:
TLS就是SSL的升级版,原理都一样的
2015年4月29日 18:31 | # | 引用
鬼知道 说:
我想知道,既然是用DH作为共享密钥的生成和交换DH所需的随机函数,那为什么还需要第一和第二阶段的随机函数呢?
2015年7月20日 23:01 | # | 引用
Edem 说:
ssl的流程写的很清楚 赞一个
2015年8月14日 12:55 | # | 引用
byronhe 说:
https://blog.helong.info/blog/2015/09/06/tls-protocol-analysis-and-crypto-protocol-design/
供参考
2015年9月 9日 18:27 | # | 引用
mk 说:
CA的作用之一是来确保server的合法性 如果仅仅使用DH无法确保server的合法性,另外依旧存在被中间人攻击的可能性
2015年12月23日 20:23 | # | 引用
bobjiao 说:
其实我也有同问,查了DH算法明白了.其实DH还是有自己的密钥,这个密钥由于计算离散对数是十分困难的,所以第三方很难破解或者说现今是不可能的.
2016年1月 4日 13:36 | # | 引用
load 说:
有大厂就是这种方案,需要proxy server去一个共享存储里面读取
还有几个请问下,就是如何跟源站之间协商session key,
源站的web server也需要做相应改造吧
cloudflare的做法是否已经被ssl的rfc文档接受?
2016年4月14日 11:50 | # | 引用
字节流 说:
第三节DH算法的握手阶段的配图,Visitor 是通过两个随机数生成的 session key,而 CloudFlare 是通过两个随机数和 Premaster secret 生成的 session key, 这两个 session key 不应该是相等的吗?不太理解,求指教。谢谢
2016年6月14日 01:05 | # | 引用
xgqfrms 说:
Defined
Protocol Year
SSL 1.0 n/a
SSL 2.0 1995
SSL 3.0 1996
TLS 1.0 1999
TLS 1.1 2006
TLS 1.2 2008
TLS 1.3 TBD
2016年7月11日 22:55 | # | 引用
别扭的键盘 说:
敢问那个图片是用什么软件生成的
2016年9月 7日 18:15 | # | 引用
董光金 说:
写的很好,很美!大赞一个
2016年10月17日 17:29 | # | 引用
mactec 说:
阮老师
DH算法实际在TLS/SSL部署中并没有RSA可靠,原因在于RSA的主要风险在于服务器私钥丢失后的第三方监听攻击
而DH算法本身有缺陷,中间人攻击更为常见,导致其实更为少用
2016年11月 3日 11:25 | # | 引用
pure 说:
大图不知道是挂了还是要VPN啊
2016年11月 3日 14:34 | # | 引用
振宇 说:
朋友我对你的说法稍有异议,Server端的私钥丢失这个属于很大的故障了吧? 我认为RSA算法的缺陷就是无法证明共匙被替换后,导致的中间人攻击问题。而DH算法本身也是无法避免中间人攻击问题的,所以在上面的实例图中,阮老师加入了数字证书的逻辑。无论是RSA还是DH都需要客户端通过CA的公共钥匙解析到数字证书中存在的server端公钥(rsa),说明一下这边DH算法传递的公共数据我们也可当公钥来看(理解方便)。
另外想请教一下层主,为什么DH更容易被中间人攻击?
2016年11月28日 15:52 | # | 引用
郭力勉 说:
DH算法本来就是轻易中间人攻击的,所以在SSL的基础上DH算法,可以保证没有中间人啊
2017年1月13日 09:01 | # | 引用
健锋 说:
整个握手阶段都不加密(也没法加密),都是明文的。因此,如果有人窃听通信,他可以知道双方选择的加密方法,以及三个随机数中的两个。整个通话的安全,只取决于第三个随机数(Premaster secret)能不能被破解。
窃听的能否自己伪造成客户端,提取证书中的公钥,做后续的操作呢
2017年3月17日 18:31 | # | 引用
netlibo 说:
有没有考虑过集中session管理也是另一个单点故障的源头?再做一层集群?
纯讨论,其实,没有最好,只有最适合。
另外,token模式在动态扩容方面还是有点优势的。
2017年3月21日 14:16 | # | 引用
葛新 说:
这里的session应该是操作系统实现的吧,属于SSL协议部分了,并不是应用级的session
2017年3月21日 21:57 | # | 引用
葛新 说:
有一些问题想请教作者。
我们知道浏览器在访问一个站点的时候,会同时建立多个TCP连接去下载资源,那是不是同一个浏览器每个TCP连接都需要与服务器端握手交换密钥然后在传输数据,还是只进行一次密钥交换,然后所有TCP连接共享
2017年3月21日 22:03 | # | 引用
Frank 说:
session key服务端生成了怎么传给客户端呢?
2017年4月17日 10:52 | # | 引用
hytrix 说:
第三个随机数是对称密钥的话,那前面两个随机数什么作用?
2017年4月21日 01:32 | # | 引用
Garen 说:
是为了确认双方支持安全协议形式,和客户端来访的安全性吧
2017年4月26日 19:11 | # | 引用
member 说:
大家看一下DH加密部分,ServerDH参数是使用了私钥加密了(还是签名?)之后再传递到客户端的,客户端用公钥解密后,生成ClientDH参数,此时随机数已经包含在ClientDH 参数中,服务器收到ClientDH,结合ServerDH,析构出随机数。
然后开始正常的加密通讯。
但是图中并没有说明 Private Key 在哪里,因为私钥不可能存放在CloudFlare,肯定是存放在自己主机上,那么这图就少一个与主机通信的环节,
2017年5月11日 14:56 | # | 引用
*** 说:
一峰同志真的很优秀!
2017年6月14日 09:24 | # | 引用
涂有 说:
请问你用的画图软件是什么?挺好看的
2017年8月14日 18:15 | # | 引用
Robin 说:
您说道:服务器的公钥和私钥只用于加密和解密"对话密钥"(非对称加密),无其他作用。
这里的对话秘钥就是sessionkey吧,既然客户端和服务端都有sessionkey,不传这个sessionkey就好了啊,为什么要加密sessionkey呢?
2017年9月29日 19:05 | # | 引用
Victor Lv 说:
深入浅出,写的很棒!
2018年1月22日 16:36 | # | 引用
steam 说:
premaster secret 是怎么生成的?没太看懂,感觉是凭空出来的
2018年1月26日 03:11 | # | 引用
steam 说:
还有一个问题,既然 client random 和 server random 都是明文传输的,那么就是说这两个数是可以被中间人获取的,那这两个随机数又有什么意义呢?
2018年1月26日 03:18 | # | 引用
sua7 说:
受教受教 打算把文章从头看起 谢谢! 希望多出点这样的安全系列文章!
2018年2月23日 18:21 | # | 引用
hhuua 说:
在他的另一篇文章里有说:"pre master的存在在于SSL协议不信任每个主机都能产生完全随机的随机数,如果随机数不随机,那么pre master secret就有可能被猜出来,那么仅适用pre master secret作为密钥就不合适了,因此必须引入新的随机因素,那么客户端和服务器加上pre master secret三个随机数一同生成的密钥就不容易被猜出了,一个伪随机可能完全不随机,可是是三个伪随机就十分接近随机了,每增加一个自由度,随机性增加的可不是一。"
2018年3月16日 16:08 | # | 引用
BING 说:
client不信任server是否是真的随机数,所以client自己提供一个随机数;同时server也不信任client是否有真的随机数,所以server自己也提供一个随机数。
2018年5月 2日 13:46 | # | 引用
steam 说:
赞!这个解释非常有说服力!
能麻烦再解释下 premaster secret 是怎么生成的吗?就是客户端根据 RSA 算法,自己随机生成的吗?
2018年6月27日 21:10 | # | 引用
maosi 说:
可以参考下面链接中的"随机密码串"部分
http://blog.jobbole.com/48369
2018年7月10日 14:25 | # | 引用
8090 说:
@爱国者:
我也有同样的疑惑,请问您解决了吗?
2018年8月 1日 16:13 | # | 引用
張旭 说:
太精彩了!
非常喜歡讀您的文章!
2019年1月19日 12:55 | # | 引用
pluto 说:
第一步,爱丽丝给出协议版本号、一个客户端生成的随机数(Client random),以及客户端支持的加密方法。
第二步,鲍勃确认双方使用的加密方法,并给出数字证书、以及一个服务器生成的随机数(Server random)。
--前两步如果是http的话,两个随机数会直接暴露,还有什么作用呢?
2020年4月18日 20:42 | # | 引用
nick 说:
网站模板可以给我一份吗我也想要这样的,现在用wordpress
2020年6月15日 23:01 | # | 引用
xingxying 说:
看着看着就2020年了
2021年4月20日 16:52 | # | 引用
Vonger 说:
阮老师,或者在座的各位老师,我有一个疑问。
就是握手阶段为什么会产生三个随机数,阮老师也说到了实际上前两个随机数并不安全,虽然有解释道三个随机数生成的对话密钥会更安全,但是核心还是在最后的Premaster secret,因此前两个随机数是否有必要?
我在网上看到的文章有说只需要最后的Premaster secret,有说总共需要三个随机数的。当时我比较倾向于后一种,但是在一次腾讯面试中被问到这个问题时,面试官质疑了我问我怎么可能会需要三个随机数,我也很懵逼。面试过后我查看了《图解HTTP》,上面描述的握手阶段是只产生了最后衣蛾个随机数Premaster secret的。
希望能得到解答,谢谢
2021年5月22日 18:21 | # | 引用
zippo 说:
sessionId 一般不是保存在cookie中吗?如果sessionid被截获,上一次链接断开,岂不是就能和服务器直接交换信息了?
2022年1月 7日 20:09 | # | 引用
taro 说:
误人子弟,不同厂商实现不一样,不代表通用的做法啊
2022年5月19日 13:00 | # | 引用
ǝɔɐǝԀʎzɐɹϽ 说:
我想请问,虽然CDN没拿到服务器的私钥,但是知道SSL对话所用的对称密钥对吧?
那CDN是可以解密客户端到服务器的数据的。
如果我使用一个受到审查的CDN去传输翻墙数据,那么我应该在SSL里面再使用一层加密处理我真正的翻墙数据。
对吗?
2022年5月27日 12:03 | # | 引用
yhding 说:
受益匪浅,发现 ssl handshake(Diffie-Hellman) without keyless 图片,客户端这块儿 premaster secret 并未没有参与到 seesion key的计算中
2022年6月30日 09:43 | # | 引用