七十一、进阶篇-浅谈TLS协议(上篇)

目前HTTPS的方案就是采用TLS协议,TLS协议是理解HTTPS的关键,本篇文章来从宏观了解TLS协议。

友情提示:本文与本系列前文中多篇文章知识点关联,并且更进一步,还请充分理解前文再来阅读本文。

七十一、进阶篇-浅谈TLS协议(上篇)

一、TLS和SSL

读者朋友们一定听说过SSL协议,也可能听说过TLS协议,在理解的时候可以认为两者是一样的,TLS协议是SSL协议的升级版

SSL 协议已经不再被认为是安全的了,现在我们使用的是 TLS 协议。不过因为历史原因,有些软件还是以 SSL 命名的,例如著名的 OpenSSL 。

TLS 是 Transport Layer Security 的缩写,表示“传输层安全”。TLS 协议是 SSL 协议的后继者,是用于确保网络连接安全的最常用加密协议。

TLS 协议有三个版本:1.1、1.2和1.3,目前使用最广泛的是1.2版本,本文着重基于1.2版本讨论。

注意,TLS是一个独立的协议,不只HTTP能用,其他的协议也可以组合使用,比如FTP协议、SMTP协议等等,这就是分层带来的好处!

七十一、进阶篇-浅谈TLS协议(上篇)

二、TLS的位置

在具体了解TLS协议前,我们先了解其在TCP/IP协议中的定位,之前我们学习的经典的TCP/IP四层模型如下:

七十一、进阶篇-浅谈TLS协议(上篇)

那么TLS协议处于什么位置呢?

七十一、进阶篇-浅谈TLS协议(上篇)

容易看出,TLS协议位于应用层和传输层之间,HTTP是基于TCP的应用,因此我们可以说TLS位于HTTP和TCP之间,构建在TCP之上。

这种HTTP和TLS的协议组合就是HTTPS,HTTPS拥有HTTP的所有特征,并且HTTP的消息由TLS协议进行安全保护。

七十一、进阶篇-浅谈TLS协议(上篇)

HTTPS的默认端口是443,浏览器访问HTTPS网站时,就是在连接服务器的443端口,将所有HTTP数据传递给TLS协议,TLS协议加密后传递给TCP协议,通过下面的IP路由协议以及更下层的服务完成数据传输。

TLS只是一个协议,TLS协议的加密和解密工作具体是谁做呢?浏览器和Web服务器都可以调用操作系统上的OpenSSL库来完成TLS协议的具体工作

可以看出来,TLS协议具体实现对于我们开发者来说是透明的,数据到达应用层时已经是标准的解密后的HTTP报文,因此上层应用在编写代码时无须关注是HTTP协议还是HTTPS协议,程序都按照HTTP标准处理HTTP头部、输出内容即可。

此外,TLS一般构建在TCP之上,但是也可以构建在UDP之上,称为DTLS ( Datagram Transport Layer Security ),只是DTLS在Web中使用得比较少。

七十一、进阶篇-浅谈TLS协议(上篇)

三、TLS的核心步骤

TLS的实现虽然对于开发者来说是透明的,但是我们还是要了解其宏观原理,我们已经学习了不少密码学算法,已经具备了基础。

我们理一下TLS协议的关键设计步骤:

  • 首先解决中间人攻击问题,客户端无法确认公钥确实来自真实服务器,需要结合PKI技术进行身份认证;

  • 传输的数据必须具有机密性和完整性,一般采用对称加密算法和HMAC算法,这些算法需要一系列的密钥块,如何生成呢?

  • 所有的密钥块可以由主密钥生成,主密钥就是我们之前说的会话密钥,可使用密码衍生算法将主密钥转换为多个密钥块;

  • 主密钥又来自预备主密钥,预备主密钥通过密码衍生算法生成主密钥,预备主密钥通过RSA或DH算法协商而来;

因此,核心步骤是:身份认证、密钥协商、数据加密,需要将其串联起来,本文假设已经完成了身份认证,下面的问题是要解决密钥协商和数据加密问题,我们来看看TLS是如何做的。

七十一、进阶篇-浅谈TLS协议(上篇)

四、加密算法和MAC算法

前面学习MAC算法的时候,我们说过这么一句话:加密算法不提供完整性,加密的同时必须引入MAC算法避免消息被篡改,两者结合保障机密性和完整性。

加密算法和MAC算法如影随形,有加密算法必定有MAC算法,可以认为是一个整体。

为了对数据进行加密,可以采用对称加密算法或公开密钥算法。

加密算法我们之前已经说过,虽然公开密钥算法具有加密解密功能,但是由于运算慢的缺陷,在数据量大的情况下不能使用,唯一可行的方案是对称加密算法,比如AES、DES算法。

在Web应用中使用比较多的MAC算法是HMAC算法,比如HMAC-SHA-1、HMAC-SHA256算法。

问题来了,对称加密算法和MAC算法是如何选择出来的呢?这里不得不提另外一个关键字:密码套件

在TLS协议中,需要协商双方都认可的密钥套件,密码套件决定了本次连接采用哪一种加密算法、密钥协商算法、HMAC算法,本节我们不展开说明,下篇文章详细介绍,本节只要知道客户端和服务端在连接阶段需要协商出双方都认可的一些密码学算法,即密码套件。

假设客户端和服务端协商出统一的加密标准是AES-128-CBC-PKCS#7,HMAC标准采用HMAC-SHA256,客户端和服务端必须持有相同的AES密钥、HMAC密钥,这些关键值称为密钥块。

我们知道,数据是要加密传输,但是加密数据需要密钥,那么剩下的问题就是如何安全传输密钥,此外由于客户端和服务端互不认识,且客户端数量众多,这里必须采取动态密钥分配方式,那么密钥协商算法登场。

七十一、进阶篇-浅谈TLS协议(上篇)

五、密钥协商算法

在学习密钥协商算法的时候,我们说会协商出一个会话密钥,当时核心是为了介绍协商算法本身,因此简化了对密钥的说明,实际上并不是那么简单,我们来看看在TLS中,各种加密算法最终用到的密钥块是如何一步一步协商和推导出来的。

在TLS中,第一步密钥协商出来的密钥称之为预备主密钥(Premaster Secret),其特点为:

  • 每次客户端和服务端连接时都会生成不同的预备主密钥;

  • 每次客户端和服务端断开连接后会自动从内存中消失,不会持久化保存;

  • 必须是随机的不能被猜测,也必须是保密的不能被截获;

那么在某个连接中,客户端和服务端使用哪种密钥协商算法呢?答案还是密钥套件,由客户端和服务端共同决定。

在HTTPS中,一般采用RSA或者DH算法协商预备主密钥。

  • RSA算法

    • 客户端向服务器端发起连接请求,服务器端发送 RSA 密钥对的公钥给客户端;

    • 客户端通过随机数生成器生成一个预备主密钥,用服务器的公钥加密并发送给服务器端;

    • 服务器解密预备主密钥,假如能够正确解密,则说明客户端和服务器端共同协商出一个预备主密钥;

  • DH算法

    • 客户端向服务器端发起连接请求;

    • 服务器端生成 RSA 密钥对,并将服务器公钥发送给客户端,客户端依靠证书链来验证身份,确保公钥确实来自真实服务器,详细见上篇文章

    • 服务器端生成 DH 参数和服务器 DH 密钥对,用 RSA 私钥签名 DH 参数和服务器 DH 公钥,最后将签名值、 DH 参数 、服务器 DH 公钥发送给客户端;

    • 客户端通过服务器 RSA 的公钥验证签名,获取到 DH 参数和服务器 DH 公钥;

    • 客户端通 DH 参数生成客户端 DH 密钥对 并将客户端 DH 公钥发送给服务器端;

    • 客户端通过客户端 DH 私钥和服务器端 DH 公钥计算出预备主密钥;

    • 服务器端接收到客户端的 DH 公钥,结合服务器的 DH 私钥计算出预备主密钥;

    • 最终客户端和服务器端计算出的预备主密钥能够保持一致;

RSA密钥协商过程极其简单,我们不再赘述。

读者朋友们如果看过之前的文章,一定会发现跟之前说明的DH密钥协商算法流程有些变化,其核心变化为标绿加粗字体,在HTTPS中,在密钥协商开始前,客户端先结合证书进行身份认证流程,获取到服务器公钥,服务器在发送DH参数和服务器DH公钥之前会使用服务器私钥对这两个值进行签名运算,客户端获取后使用服务器公钥进行验签,确保传递的值没有被篡改。(这里涉及的公开密钥算法密钥对较多,一个是服务器证书密钥对–》用于身份认证,一个是DH密钥对–》用于协商密钥,还有是CA机构本身的密钥对–》用于证书链验签,还请务必区分好!

DH 算法最大的优点就在于预备主密钥是客户端和服务器端共同计算出来的,只有经过消息互换才能计算出预备主密钥,不过相比于RSA协商算法,会多出来很多步骤,不过我们还是选择DH算法,原因下篇文章揭晓。

注意,在公开密钥算法中,网络通信存在中间人攻击,客户端无法确认公钥确实来自真实服务器,在HTTPS协议中必须引入PKI术解决身份验证的问题,这也是上一篇文章着重探讨的事情,本节就显得很轻松了,只有身份认证通过后才会进行密钥协商等流程。

七十一、进阶篇-浅谈TLS协议(上篇)

六、密钥衍生算法

借助PKI技术和密钥协商算法,我们终于安全拿到了预备主密钥,但是名字中有个预备,显然不是最终用来加密的密钥。

本文第四段落中还提及到:客户端和服务端必须持有相同的AES密钥、HMAC密钥,这些关键值称为密钥块,显然,密钥块才是最终用来加密和解密使用的对象,它是如何来的呢?

机密性和和完整性需要的密钥块是通过密钥衍生算法计算出来的,而且需要经过两次运算:

  • 预备主密钥转换出固定长度的主密钥;

  • 主密钥转换出任意数量、任意长度的密钥块。

TLS SSL 协议中使用一种称为 Pseudo-Random Function (PRF) 的函数进行密码块的推导。

针对所有的密钥交换算法,最终都会使用相同的算法将预主密钥(pre master secret)转换成主密钥(master secret)。一旦主密钥生成,预主密钥也就应该删除了。

master_secret = PRF(pre_master_secret, "master secret",                          ClientHello.random + ServerHello.random)                          [0..47];

生成过程很简单,拿到预主密钥,结合Client随机数和Server随机数,调用PRF(pseudo-random function)伪随机函数,截取48位,最后得到48字节的主密钥。

因此要极力避免攻击者获取预备主密钥,如果攻击者获取到了预备主密钥,加上 ClientHello.random 和 ServerHello.random 传输过程中是不加密的,也容易获取,那么攻击者就可以合成主密钥并进一步导出会话密钥,这样整个加密过程就被完全破解了。

好了,拥有了主密钥后,如何生成各种加密算法所需要的密钥块呢?比如AES需要的密钥块?

还是通过上面的PRF函数来计算,只是相对于生成主密钥的参数,生成各密钥块的入参会发生变化。

key_block = PRF(SecurityParameters.master_secret,          "key expansion",          SecurityParameters.server_random +          SecurityParameters.client_random);

主密钥被用作一个熵源,密钥块的长度和个数取决于协商出来的密码套件,更准确的说是取决于加密参数 SecurityParameters ,直到产生足够的输出。然后,key_block会按照如下方式分开:

client_write_MAC_key[SecurityParameters.mac_key_length]server_write_MAC_key[SecurityParameters.mac_key_length]client_write_key[SecurityParameters.enc_key_length]server_write_key[SecurityParameters.enc_key_length]client_write_IV[SecurityParameters.fixed_iv_length]server_write_IV[SecurityParameters.fixed_iv_length]

client_write_keyserver_write_keyclient_write_MAC_key 和 server_write_MAC_key 是加密和消息验证码需要的密钥。如果是分组加密方式,还需要初始化向量write_IV

Client 和 Server 分别拥有自己的一套密钥,使用的密钥是不同的。

当加密时,客户端使用客户端的client_write_key密钥块加密消息并发送,服务器收到消息后,使用客户端的client_write_key密钥块解密消息。对于服务器流程也是一样。

通过PKI技术中的证书成功完成身份校验后,双方只要通过密钥协商算法协商出预备主密钥即可,剩下的密钥可通过前期握手交换的信息全部计算出来,获取到了密钥块后,剩下的就是数据加密和解密的过程了。

本文仅从宏观上浅谈了TLS协议,未讨论TLS协议本身的交互流程和细节,下篇继续讨论TLS协议。

本文完,下篇见!

原文始发于微信公众号(幕后哈土奇):七十一、进阶篇-浅谈TLS协议(上篇)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/113119.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!