概述
TLS是现在广泛使用的安全协议,全名为传输层安全协议(Transport Layer Security).它的前身是SSL,即安全套接层(Secure Socket Layer).
网景公司(Netscape)在1994年推出首版网页浏览器,网景导航者时,推出HTTPS协议,以SSL进行加密,这是SSL的起源。
后来,Google在04年发布 在SSL 3.0中发现设计缺陷,建议禁用此一协议。攻击者可以向TLS发送虚假错误提示,然后将安全连接强行降级到过时且不安全的SSL 3.0,然后就可以利用其中的设计漏洞窃取敏感信息。最后各大公司都选择了强制使用TLS.
目前SSL/TLS已成为互联网上保密通讯的工业标准
更新: 这个SSL/TLS就像是在应用层和传输层中间多加的半层. 其实就是库嘛, 应用程序可以选择性的进行调用. 以Web服务为例, 如果没有调用的话就是http, 如果调用了的话就是https了.反正提供了API. 二者虽然只有一个字的差距但是却又很大的不同的. 一个是文本格式的, 一个是二进制的格式的.
尽管他自己是半个层, 但是其内部也是分了很多层的(进行了分层设计), 简单的说一下:
- 最底层: 基础算法原语的实现, aes, rsa, md5
- 向上一层: 各种算法的实现
- 再向上一层: 组合算法实现的半成品
- 用各种组件拼装而成的种种成品密码学协议/软件:
- tls, ssh, ...
正片开始
提到了TLS,就一定要说一下HTTPS了,一般对HTTPS的定义是HTTP over SSL/HTTP over TLS/HTTP over Secure
.
而提到了HTTPS,有不得不说一下浏览器了.那么我来慢慢按照顺序来说一下.
首先,HTTPS借由HTTP(如果对HTTP不熟悉可以考虑看一下隔壁的HTTP阅读笔记
)来传输信息,但为了某些需要,要加密某些信息,此时它就借助了SSL/TLS来加密传输的数据包.一般的,HTTPS的默认使用端口为443
.
最重要的部分就是协议实现的方式了.
下面来说下:(可以结合下面的图来看,超清版的.SVG)
首先客户端向Web服务器发送一个HTTPS请求,该请求包含了客户端的条件以及一个随机数.关键字:{ 本地条件 }
- 具体内容包括:支持的协议版本,比如TLS1.0版,一个客户端生成的随机数(稍后用于生成“会话密钥”),支持的加密算法(如RSA公钥加密)和支持的压缩算法。
此时,客户端的随机数被Server端获得.
然后收到一个Server回应消息,这个回应中确定了双方在后来要使用的各种连接参数.关键字:{ 确定参数 }
- 这次的回应包括:确认使用的加密通信协议版本,比如TLS 1.2版本(如果浏览器与服务器支持的版本不一致,服务器关闭加密通信),一个服务器生成的随机数(稍后用于生成“对话密钥”),确认使用的加密方法(如RSA公钥加密),服务器证书。
此时,双方手中都有了双方的随机数.
至此,Phase 1结束.
- { Phase1中交换了随机数,确定了连接参数 }
再然后当双方知道了连接参数,客户端与服务器交换证书(依靠被选择的公钥系统)(Phase2-Phase3)
服务器端向客户端发送自己的证书和公钥并要求客户端提供证书. 看到这里,想必会有这样的疑问:客户端哪里来的证书?
我认为,本机的电子证书是通过浏览器中预设的CA来获取的.
SSL 服务器证书提供加密和安全功能。
客户端证书提供用户身份验证功能。
客户端证书由证书颁发机构颁发给用户。
客户端这边,通过CA的公钥解密服务器端的证书,还会检测是否被吊销, 确认是否有效.
- 所以说,这里的证书是经过了认证中心的私钥加密的
关键字:{ 确认服务器端身份 }
此时,客户端手中多了服务器端的公钥.
至此,Phase2结束.
- {Phase2中客户端验证了服务器的身份}
接着根据之前的请求,客户端向服务器端发送自己的证书和自己的公钥.
客户端有证书即双向身份认证,没证书时随机生成公钥。
服务器端对客户端发来的证书进行检查,如果有问题会直接中断私密通信.
然后,客户端再次生成一个随机数,注意,此时生成的随机数是经过了服务器端公钥的加密的,接着将其发送到了服务器端.
当服务器端收到了这个随机数,(我们把他叫做pre-master-secret
),双方会根据之前商定的加密方法,对之前的两个随机数加上这个PMS,生成一个会话密钥(MS
).
此时,服务器端手中自己的公钥和私钥,以及MS
客户端手中有自己的公钥和私钥,以及MS
至此,Phase3结束.
- {Phase3中双方得到了会话密钥}
最后,双方关键数据的加密传输均使用这个“会话密钥”--主密钥
结束SSL握手.
至此,全部的SSL握手结束.
SSL/TLS的延时问题
既然HTTPS的数据传递是相对安全的,那为什么不给每一个域名都配上HTTPS呢?
原因很简单,延时,因为复杂的握手机制,会使得访问时间延长很多,那么到底有多少呢?
首先,HTTPS是建立在HTTP的,HTTP又是建立在TCP/IP上的,因此必定存在三次握手.
所以,我们可以得到:
HTTP耗时 = TCP握手
HTTPs耗时 = TCP握手 + SSL握手
我们可以做一个小测试:
命令行工具curl有一个w参数,可以用来测量TCP握手和SSL握手的具体耗时,以访问支付宝为例。
$ curl -w "TCP handshake: %{time_connect}, SSL handshake: %{time_appconnect}\n" -so /dev/null https://www.alipay.com
我测试的一些结果样本供参考:
TCP handshake: 0.053, SSL handshake: 0.129
TCP handshake: 0.079, SSL handshake: 0.187
TCP handshake: 0.075, SSL handshake: 0.145
TCP handshake: 0.077, SSL handshake: 0.150
从结果可以看到,SSL握手的耗时大概是TCP握手的二-三倍。
也就是说,在建立连接的阶段,HTTPs链接比HTTP链接要长2-3倍的时间,当然了,具体数字取决于CPU的快慢和网络状况。
最后,再来说说session恢复的问题
如果出于某种原因,对话中断,就需要重新握手。
之前说过,SSL是很要时间的,因此,要想出一种办法来快速恢复.
这时有两种方法可以恢复原来的session:一种叫做session ID,另一种叫做session ticket。
session ID的思想很简单,就是每一次对话都有一个编号(session ID)。如果对话中断,下次重连的时候,只要客户端给出这个编号,且服务器有这个编号的记录,双方就可以重新使用已有的"对话密钥",而不必重新生成一把。
[图片上传失败...(image-cccd4b-1523105936228)]
上图中,客户端给出session ID,服务器确认该编号存在,双方就不再进行握手阶段剩余的步骤,而直接用已有的对话密钥进行加密通信。
但是,sessionID是存储在一个服务器上的,一旦有发向另一台的请求,就又会重新开始了.
为了解决这个问题,session ticket应运而生.
[图片上传失败...(image-68ef83-1523105936228)]
上图中,客户端不再发送session ID,而是发送一个服务器在上一次对话中发送过来的session ticket。这个session ticket是加密的,只有服务器才能解密,其中包括本次对话的主要信息,比如对话密钥和加密方法。当服务器收到session ticket以后,解密后就不必重新生成对话密钥了。
补充:SSH(Secure Shell)的原理和处理过程
首先,需要知道几种不同的SSH Key,
- HOST KEY 由服务端创建, 用于对服务端进行认证
- User Key 由用户创建, 用于对用户进行验证
- Server Key 服务端创建(有效期默认为1小时) 用于加密Session Key--在SSH-2中作为一个概念而存在
- Session Key 存在于会话中, 用于对传输的数据进行加密
类似上文的SSL/TLS, SSH原理与之很相似.
需要以下几个阶段:
- 协议协商阶段 (就如同HTTPS交换信息一样)
- 服务端认证阶段
- 客户端认证阶段
- 传输阶段
阶段一:协商
SSH服务器会打开默认的22端口等待客户端的连接, 一旦客户端发起TCP连接请求, 服务端收到后就会向客户端发送SSH协议版本信息.
接着客户端就会根据版本信息与自己的版本,决定选用哪个版本的,发送给服务端.
服务端进行检查自己是否支持客户端决定选用的SSH版本, 在该过程中, 如果发现版本不兼容的情况, 任何一方都可以直接中断连接.
阶段二: 认证
此时,双方已经建立了通信通道, 要注意,此时的通道依然是明文传输.
服务端发送Host Key&Server Key带上一个128位的MD5(由一个8字节的随机数生成,用来防止IP地址欺诈),客户端收到后,会先到~/.ssh/known_hosts
文件中检查是否已经包含,如果没有会发出警告,询问用户是否要信任该主机,并附上其RSA指纹.
The authenticity of host 'host (12.18.429.21)' can't be established.
RSA key fingerprint is 98:2e:d7:e0:de:9f:ac:67:28:c2:42:2d:37:16:58:4d.
Are you sure you want to continue connecting (yes/no)?
如果有,就会进行下一步.
接着,客户端向服务器端发送Session Key, 这个时候是建立SSH隧道中最需要保密,最重要的时刻,因为session key维系着数据传输的保密性.一旦Session key泄露,整个SSH的安全机制就会变得荡然无存, 因此客户端会使用Host key和Server key对这个session key进行双重加密.
服务器端收到这个Session key,一个安全的通道就被建立起来了,双方会通过这个Session key进行数据的加密和解密.另外,在正式这个通道前, 服务端会再次要求客户端发送Session Key加密的确认信息,如果无误, 则完成服务端的认证过程.
对于客户端的认证,最常见的两种认证方式就是password和public key, 由于password的方式是一般调用的本地系统接口.因此其配置简单(或者说无需配置), 但是暴力破解是可能的.
较好的方式是使用public key的方式.
下面简单说一下, 这种方法的运作流程.
- 客户端发起一个Public Key的认证请求,并发送RSA Key的模数作为标识符.
- 服务端检查是否存在请求帐号的公钥(Linux中存储在~/.ssh/authorized _ keys文件中),以及其拥有的访问权限。如果没有则断开连接
- 服务端使用对应的公钥对一个随机的256位的字符串进行加密,并发送给客户端
- 客户端使用私钥对字符串进行解密,并将其结合session id生成一个MD5值发送给服务端。 结合session id的目的是为了避免攻击者采用重放攻击(简单的说就好像是模拟发送一个一样的请求,就像经常在Fiddier进行的一样,也可以理解成窃听到身份token,然后发送给服务端,从而获得token所有者的身份权限)
- 服务端采用同样的方式生成MD5值与客户端返回的MD5值进行比较,完成对客户端的认证.
阶段三: 传输
使用Session Key提供的对称加密算法,保证数据传输的安全.