欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 人文社科 > 生活经验 >内容正文

生活经验

从 SSLTLS 的底层实现来看 网络安全的庞大复杂体系

发布时间:2023/11/27 生活经验 74 豆豆
生活随笔 收集整理的这篇文章主要介绍了 从 SSLTLS 的底层实现来看 网络安全的庞大复杂体系 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

文章目录

    • 前言
    • 1. HTTP协议通信的问题
      • 1.1 tcpdump 抓取http 请求包
      • 1.2 报文分析
      • 1.3 HTTP 协议问题
    • 2. SSL & TLS 协议的基本介绍和历史演进
    • 3. TLS 1.2 实现加密传输的过程
      • 3.1 TLS HandShake 协议概览
      • 3.2 第一次握手:ClientHello
      • 3.3 第二次握手:从ServerHello 到 ServerHelloDone
        • 3.3.1 ServerHello
        • 3.3.2 Server Certificate
        • 3.3.3 ServerKeyExchange
        • 3.3.4 CertificateRequest
        • 3.3.5 ServerHelloDone
      • 3.4 第三次握手
        • 3.4.1 Client Certificate
        • 3.4.2 Client Key Exchange Message
        • 3.4.3 Certificate Verify
        • 3.4.4 Finished
    • 4. 参考文献

前言

近期工作需要接入http 接口到存储引擎,因为公司内网 需要保证内网安全,所有的http请求通信都需要通过 https,也就是安全的http 协议才行。这个时候,实现的http 接口也就需要支持 SSL & TLS 。这里会产生一些疑惑,http请求和https 请求的本质区别是什么?为什要有https ,也就是SSL & TLS的出现,他们要解决http 解决不了的什么问题?

这不了解还好,一了解 并深入底层 才发现 SSLTLS 的发展史已经接近整个互联网的发展史,他们底层的技术栈已经被作为互联网信息传输的基础,是一个庞大的系统。然后就不得不感叹技术之广之深,习以为常的技术却深藏奥秘 和 互联网的精髓,再看看我这种每天只想做一只只完成工作的咸鱼,相比互联网前沿探索的先辈来说真是自愧不如。

还是回归正题,先做一个SSL & TLS的笔记记录吧。

本文将从如下几个方面展开:

  1. 当前http 协议通信的问题?
  2. SSL & TLS 协议的基本介绍和历史演进?
  3. 然后从 它们的实现过程 来看 https 如何通过 SSL&TLS 解决http 的问题?

1. HTTP协议通信的问题

互联网是一个开放的环境,任何人持有一个接入网络的终端,都能够去访问其他任何服务器。而终端和服务器之间的通信内容都有可能被其他人看到/截取/修改。我们看看不使用https 通信的情况下,能够看到通信双方都互相接收发送什么内容?

1.1 tcpdump 抓取http 请求包

  • 开启一个终端: tcpdump tcp port 80 -n -A -s 0监听通过80端口的所有请求信息。

  • 开启另一个终端:通过curl 发送http请求

    curl -d "city=dongguan&appkey=8010132dcf54491a4eaa387f4db61774" "http://way.jd.com/he/freeweather"

    可以看到这里向url http://way.jd.com/he/freeweather 发送的是一个post请求,将本地用户的请求信息带着发送给了这个 url。

    最后会收到远端服务器返回的一个json字符串,表示本地用户的请求结果。

        {"code":"10000","charge":false,"msg":"查询成功", \"result":{"HeWeather5":[{"aqi":{"city": \{"aqi":"28","co":"0.5","no2":"18","o3":"87"...
    

1.2 报文分析

这个时候我们再去 tcpdump 开启的终端看看抓取到的通信的内容。

如下为截取的抓取结果,后面其实还有http 的四次挥手,不过不影响我们分析http 请求。

可以看到很明显的一点,我们通过 http 发送的不安全的请求,在第三方抓包的时候能够看到双方通信的所有内容,也就是明文通信。假如我们是一个登陆网站,那我们post 到远端服务器的个人用户名/密码/其他信息 的所有数据都会被第三方看到,当然看到的话也能够被修改,这对于处于互联网中的个人隐私来说简直是一个灾难。

这个时候,我们把curl请求的http请求切换为https,能够看到抓取到的报文信息就看不到用户信息了,基本都是密文。

1.3 HTTP 协议问题

综上,我们能够很明显得看到 http 不加密协议的问题:

  1. 窃听风险(eavesdropping):第三方可以获知通信内容。
  2. 篡改风险(tampering): 第三方可以修改通信内容
  3. 冒充风险(pretending): 第三方可以冒充他人参与通信。

而,加上了HTTPS 即 SSL & TLS 安全协议,为了解决以上是三个风险,我们期望能够达到:

  1. 所有信息都是加密传播,第三方无法窃听。

  2. 具有校验机制,一旦被篡改,通信双方会立刻发现。

  3. 配备身份证书,防止身份被冒充。

第一点的加密传输,我们能够从 tcpdump 的抓包内容中看到这个特性,第二第三点则是SSL & TLS 协议栈背后的通信的细节,我们接下来将描述这个过程。

2. SSL & TLS 协议的基本介绍和历史演进

前面我们说 安全加密通信 都是将SSLTLS 放在一起进行描述,SSL(Secure Socket Layer)和 TLS(Transport Layer Security) 都是加密协议,它们从作用上并没有区别,都是为了解决加密传输的问题。事实上,TLS 是 一个 SSL 比较新的版本,TSL 功能上和SSL的区别是为了解决早期 SSL的一些安全性问题。

SSL & TLS 的发展史如下:

  1. SSL 1.0 – 因为一些安全性问题,从来没有被公开过
  2. SSL 2.0 – 1995年发布。因为一些安全性问题,在2011年被废弃。
  3. SSL 3.0 – 1996年发布。因为一些安全性问题,在2015年被废弃。
  4. TLS 1.0 – 在1999年作为SSL 3.0 升级版本,已经在2020年废弃。
  5. TLS 1.1 – 在2006年发布,在2020年废弃。
  6. TLS 1.2 – 2008年发布。
  7. TLS 1.3 – 2018年发布。

也就是我们现在浏览器 以及 企业内部 的加密通信大多是TLS1.2 版本及以上,后续介绍的SSL & TLS 如何进行安全通信的细节是在TLS1.2 版本之上进行的。

TLS/SSL 的基本加密思路是通过 公钥加密 ,也就是客户端会先向服务端索要 公钥,然后用公钥加密信息,服务端收到信息再通过公钥进行解密。

3. TLS 1.2 实现加密传输的过程

总体介绍一下TLS/SSL 的加密过程如下:

  1. 客户端向服务器端索要并验证公钥。

  2. 双方协商生成"对话密钥"。

  3. 双方采用"对话密钥"进行加密通信。

在TLS 1.2 版本中,整个协议栈由两个协议层组成:TLS record protocolTLS HandShake protocol ,而在这两个TLS 本身的协议层之下则是一些更加可靠的传输协议(TCP这种)。

其中 TSL record protocol 主要有如下两个特性:

  • 保证链接是私密的。这一层会对数据进行加密,并且保证用于当前通信的公有密钥是唯一的,也就是只有连接者和服务器知道具体的公钥。
  • 保证链接是可靠的。

在上面的协议之下,TLS 还维护了一个 TLS HandShake protoco L,这个协议是TLS 解决 http 三个主要问题的核心协议,其允许服务器和客户端之间在进行真正的数据传输之前进行互相验证并协商加密算法 和 加密密钥。

接下来我们要详细看一下TLS HandShake protocol 的协议实现过程。

3.1 TLS HandShake 协议概览

TLS 握手协议的步骤主要是如下几步(我们前面用tcpdum 抓到的三次握手):

  1. 交换Hello Message, 主要进行一些加密算法 的验证 以及 一些伪随机数的交换。
  2. 交换一些必要的加密参数,来允许客户端和 server 认同 premaster secret的值.
  3. 交换证书和加密信息 来让客户端和服务端进行互相身份的验证。
  4. 通过 premaster secret 生成一个master 密钥 和 交换一些随机值。
  5. 将这一些安装参数提供给 上层的 TLS Record Protocol.
  6. 允许客户端和服务端在他们本地计算安全参数,从而保证即使有攻击发生,链接请求也不会在客户端或者服务端建立成功。

从服务端和客户端的角度来看,主要有如下几个步骤:

      Client                                               ServerClientHello                  -------->ServerHelloCertificate*ServerKeyExchange*CertificateRequest*<--------      ServerHelloDoneCertificate*ClientKeyExchangeCertificateVerify*[ChangeCipherSpec]Finished                     -------->[ChangeCipherSpec]<--------             FinishedApplication Data             <------->     Application Data

关于底层的HandShake结构体类型如下:

enum {hello_request(0), client_hello(1), server_hello(2),certificate(11), server_key_exchange (12),certificate_request(13), server_hello_done(14),certificate_verify(15), client_key_exchange(16),finished(20), (255)
} HandshakeType;struct {HandshakeType msg_type;    /* handshake type */uint24 length;             /* bytes in message */select (HandshakeType) {case hello_request:       HelloRequest;case client_hello:        ClientHello;case server_hello:        ServerHello;case certificate:         Certificate;case server_key_exchange: ServerKeyExchange;case certificate_request: CertificateRequest;case server_hello_done:   ServerHelloDone;case certificate_verify:  CertificateVerify;case client_key_exchange: ClientKeyExchange;case finished:            Finished;} body;
} Handshake;

3.2 第一次握手:ClientHello

首先 客户端 和服务器进行第一个的链接的时候会 发送ClientHello 请求到服务器。这个阶段主要是双方交换一些安全属性的信息。

其中ClientHello的消息结构体如下:

struct {ProtocolVersion client_version;Random random;SessionID session_id;CipherSuite cipher_suites<2..2^16-2>;CompressionMethod compression_methods<1..2^8-1>;select (extensions_present) {case false:struct {};case true:Extension extensions<0..2^16-1>;};
} ClientHello;

结构体内部的成员即是 这个 Request 客户端要发送给服务端的内容,主要包括

  1. client_version:当前TLS 协议的版本号
  2. random: 一个客户端生成的伪随机数,主要由两部分构成gmt_unix_timerandom_bytes,当前系统时间和一个28bytes的伪随机数。
  3. session_id: 客户端希望本次链接的标识。
  4. Ciper_suites :表示客户端支持的一些加密方式列表(RSA等)。
  5. compression_methods:一个客户端支持的 压缩方式的列表。

3.3 第二次握手:从ServerHello 到 ServerHelloDone

第二次握手包含五个阶段,主要是服务端的回复内容。

主要的内容如下:

  1. 确认使用的加密通信版本。如果版本不一致(比如TLS 1.2),则服务器关闭通信功能
  2. 一个服务器生成的随机数,后续用于生成对话密钥。
  3. 确认使用的加密方法,比如RSA
  4. 服务器的认证证书。
  5. Extensions,类似请求客户端证书,比如某一些企业的请求接入,需要客户端提供企业之前提供过的认证才行。

以上内容主要被以下几个请求依次发送:

3.3.1 ServerHello

这个结构体内容如下:

struct {ProtocolVersion server_version;Random random;SessionID session_id;CipherSuite cipher_suite;CompressionMethod compression_method;select (extensions_present) {case false:struct {};case true:Extension extensions<0..2^16-1>;};
} ServerHello;
  1. server_version: server 支持的 TLS 协议版本
  2. random: server 会在 client 发送过来的随机数基础上再生成一个随机数。
  3. session_id: 收到client 发送过来的session_id 之后,会从自己的session列表中查找这个id,找到了则直接复用。否则,server的session_id 会直接填充一个新的session_id返回给客户端,与此同时 也会决定使用服务端的加密算法。
  4. cipher_suite: 从客户端发送过来的 加密算法列表中选择一个加密算法。如果前面的session_id 从服务端维护的列表中找到了,则直接复用这个session_id 的加密算法。
  5. compression_method:服务端选择客户端发来的压缩算法列表中的一个。当然,如果复用了session_id,压缩算法同样也会被复用。

3.3.2 Server Certificate

用于发送服务器的认证证书到客户端。再ServerHello 消息发送之后发送,消息结构体如下:

struct {ASN.1Cert certificate_list<0..2^24-1>;
} Certificate;
  • certificate_list 证书列表。第一个证书必须是发送者的证书。后续的每一个证书必须证明前面的证书是合理的。

同样,如果服务端想要客户端的证书,那客户端发送过来的证书也需要按照这种方式发送。

3.3.3 ServerKeyExchange

在服务端发送了认证证书之后会发送。这个请求发送的原因是 服务端认为自己发送给客户端的认证证书并没有包含足够的数据来允许客户端交换自己的 premaster key。如果使用如下交换密钥算法则客户端会被允许交换:DHE_DSS, DHE_RSA, DH_anon;使用如下交换算法,则客户端不会交换master key:RSA, DH_DSS, DH_RSA。

它的数据结构如下:

struct {select (KeyExchangeAlgorithm) {case dh_anon:ServerDHParams params;case dhe_dss:case dhe_rsa:ServerDHParams params;digitally-signed struct {opaque client_random[32];opaque server_random[32];ServerDHParams params;} signed_params;case rsa:case dh_dss:case dh_rsa:struct {} ;/* message is omitted for rsa, dh_dss, and dh_rsa *//* may be extended, e.g., for ECDH -- see [TLSECC] */};
} ServerKeyExchange;
  1. param: 服务器key的交换参数
    主要包含一些交换算法:

    enum { dhe_dss, dhe_rsa, dh_anon, rsa, dh_dss, dh_rsa/* may be extended, e.g., for ECDH -- see [TLSECC] */} KeyExchangeAlgorithm;struct {opaque dh_p<1..2^16-1>;opaque dh_g<1..2^16-1>;opaque dh_Ys<1..2^16-1>;
    } ServerDHParams;     /* Ephemeral DH parameters */
    
  2. signed_params: 对于非匿名密钥的交换,服务器会附加这个参数,标识自己(非匿名密钥 太了解)

3.3.4 CertificateRequest

对于非匿名服务器(企业认证的服务器)来说,会为注册用户发送一个客户端证书,注册用户接入的时候服务端也会请求客户端的认证证书。也就是整体描述 从ServerHello 到 ServerHelloDone 内容的第五段消息。

消息结构体如下:

struct {ClientCertificateType certificate_types<1..2^8-1>;SignatureAndHashAlgorithmsupported_signature_algorithms<2^16-1>;DistinguishedName certificate_authorities<0..2^16-1>;
} CertificateRequest;
  1. certificate_types 服务端为客户端提供的认证证书类型列表

    enum {rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),rsa_ephemeral_dh_RESERVED(5), dss_ephemeral_dh_RESERVED(6),fortezza_dms_RESERVED(20), (255)
    } ClientCertificateType;
    
  2. supported_signature_algorithms, 服务端支持的签名/hash 验证算法的列表

  3. certificate_authorities 可信的出版证书机构的名称。

3.3.5 ServerHelloDone

服务端在前面的消息发送完成之后会发送这个消息,表示服务端的消息已经发送完毕,客户端可以进行证书校验 以及 判断是否能够接受服务端的公钥,而服务端则会等待客户端的回复。

3.4 第三次握手

客户端校验服务端的认证证书,如果证书不是可信的机构颁布 或者 证书中的域名与实际的域名不匹配,或者证书已经过期,就会向客户端显示一个告警,由客户端选择是否继续访问。

如果证书没有问题,客户端就会从证书中取出服务端的公钥,向服务端发送如下内容:

  1. 一个随机数。该随机数用服务器公钥加密,防止被窃听。
  2. 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送
  3. 客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供服务器校验。
  4. 如果服务端需要客户端提供可信证书,那客户端也需要发送一个认证证书。

这一次握手对应客户端的三个请求,从Client Certificate 到 Finish 。

3.4.1 Client Certificate

这个请求发送的要求是 服务端 请求客户端的认证证书。

证书的格式和服务端的类似。

3.4.2 Client Key Exchange Message

客户端的编码改变通知。这个请求是无论什么时候必须要发送给服务端的。表示客户端任何 和 服务端协商的premaster-key,后续的通信都将通过这个密钥进行。

选择哪一种编码算法取决于服务端ServerKeyExchanged 请求中选择的 交换算法。

消息结构体如下:

struct {select (KeyExchangeAlgorithm) {case rsa:EncryptedPreMasterSecret;case dhe_dss:case dhe_rsa:case dh_dss:case dh_rsa:case dh_anon:ClientDiffieHellmanPublic;} exchange_keys;
} ClientKeyExchange;

3.4.3 Certificate Verify

客户端认证服务端的证书。

struct {digitally-signed struct {opaque handshake_messages[handshake_messages_length];}
} CertificateVerify;

这个结构体中的 handshake_messages 变量引用了从 client hello 到 当前消息之前的所有握手阶段的消息。

3.4.4 Finished

这个完成握手的请求会在客户端的编码改变请求 以及 证书验证请求发送之后发送。Finished 请求是一个被之前握手阶段协商的算法、公钥和对称密钥保护的消息。在这个消息发送完毕收到服务端对客户端Finished 消息回复之后 两者将通过协商后的加密算法进行通信。

再次看看整个https 的三次握手步骤:

      Client                                               ServerClientHello                  -------->ServerHelloCertificate*ServerKeyExchange*CertificateRequest*<--------      ServerHelloDoneCertificate*ClientKeyExchangeCertificateVerify*[ChangeCipherSpec]Finished                     -------->[ChangeCipherSpec]<--------             FinishedApplication Data             <------->     Application Data

可以看到,服务端收到客户端的Finished消息之后,会回复:

  1. 服务端的编码改变通知,表示后续服务端将使用协商好的对称密钥加密 以及 pre-masterkey 公钥进行解密。
  2. 服务端结束握手的通知。

之后就是用协商好的加密密钥 进行 应用数据的加解密传输了。

可以看到,在第三次握手结束后,服务端和客户端都拥有了三个随机数(客户端ClientHello生成的,服务端ServerHello生成的,客户端ClientKeyExchangeMessage生成的),这三个随机数能够保证整个加密过程的保密性(密文很难被解析到);同时 认证证书 的存在 也保证了通信的可靠性(也就是为什么不推荐大家访问浏览器报警证书不匹配问题的网站,访问的网站没有使用版本匹配/最新 的证书,无法保证传输数据的保密性)。

4. 参考文献

https://kinsta.com/knowledgebase/tls-vs-ssl/

TLS 1.2 reference detail

总结

以上是生活随笔为你收集整理的从 SSLTLS 的底层实现来看 网络安全的庞大复杂体系的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。