HTTPS那些协议:TLS, SSL, SNI, ALPN, NPN

Posted 武汉中继者

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HTTPS那些协议:TLS, SSL, SNI, ALPN, NPN相关的知识,希望对你有一定的参考价值。

如今 HTTPS 已经普遍应用了,在带来安全性的同时也确实给 Web 引入了更多复杂的概念。这其中就包括一系列从没见过的网络协议。现在 Harttle 从  HTTPS 的原理出发,尝试以最通俗的方式来解读 HTTPS 涉及的这些协议。


[
HTTPS 概要
]


HTTPS 是建立在安全通信之上的 HTTP,使用传输层加密(TLS 或 SSL)的手段。其目的是保护用户隐私(比如防止经过的网络节点截获 HTTP  内容)和数据完整性(比如运营商强插广告),就是端到端加密来防止中间人攻击。

TLS/SSL 是在传输层之上应用层之下的协议,因此 HTTP 协议的内容不受影响。这些加密采用非对称加密算法因此需要一个官方来发布公钥,这就是  密钥基础设施(CA)。因此各浏览器会内置一些 CA 的根证书,这些 CA 可以进一步授权其他的域名,这样你的浏览器就可以对正在访问的域名进行身份认证。

如果你要自己的服务也支持 HTTPS 去 CA 注册自己的域名就可以了。有一些免费的 CA 比如 GoDaddy, Let’s Encrypt,  CloudFlare 等可以选择。



[
HTTPS 交互示例
]


以下 Wireshark 日志记录了一个发往 https://github.com/harttle 的 GET  请求,可以看到主要的几个协议的交互过程:

  • TCP。前三行完成一对 SYN/ACK(即俗称的三次握手),至此 TCP 连接已经成功建立。

  • TLS。4-5 行开始了 TLS 握手,建立这个加密层。

  • TLS 有众多扩展协议比如 SNI,NPN,ALPN 等(见下文),就发生在 TLS 的 ClientHello 和 ServerHello  阶段。

HTTPS那些协议:TLS, SSL, SNI, ALPN, NPN



[
TLS/SSL
]


TLS 的前身是 SSL,TCP/IP 协议栈中运行在 TCP 之上,用来交换密钥并形成一个加密层(Record Layer)。 TLS 是 HTTPS  的核心协议,HTTPS 交互与 HTTP 交互的主要区别就在这一层:

开始传输密文前需要进行互换密钥、验证服务器证书等准备工作,因此 TLS 也存在握手阶段,主要步骤为:客户端发送 ClientHello,服务器发送  ServerHello,服务器继续发送 Certificate,然后互相发送 KeyExchange 消息,最后发送 ChangeCipherSpec  来通知对方后续都是密文。具体交互和协议字段请参考 RFC 5246(TLSv1.2)和 RFC 6176(TLSv2.0)。

TLS 作为 TCP/IP 协议栈中的加密协议有广泛的用途,为支持通用机制的协议扩展,定义了 RFC 4366 - TLS Extensions。 TLS  先后被邮件服务、Web 服务、FTP 等采用,这里有一个 扩展协议列表。

本文关注其中 Web 服务(HTTPS)相关的扩展,如 SNI, NPN, ALPN。这些协议通过扩展 TLS 的   ClientHello/ServerHello 消息为 TLS 增加新的功能。为此我们先看一下 ClientHello 消息的结构(ServerHello  类似):

  1. struct { 

  2.     ProtocolVersion client_version; 

  3.     Random random; 

  4.     SessionID session_id; 

  5.     CipherSuite cipher_suites<2..2^16-2>; 

  6.     CompressionMethod compression_methods<1..2^8-1>; 

  7.     select (extensions_present) { 

  8.         case false: 

  9.             struct {}; 

  10.         case true: 

  11.             Extension extensions<0..2^16-1>; 

  12.     }; 

  13. } ClientHello; 


注意最后一个字段,最多可以有 65536 个 Extension,其中 Extension 定义为一个两字节的 ExtensionType  以及对应的不透明数据。下文的 SNI,NPN,ALPN 都是其中之一。



[
SNI
]


SNI(Server Name Indication)指定了 TLS 握手时要连接的 主机名。 SNI 协议是为了支持同一个  IP(和端口)支持多个域名。

因为在 TLS   握手期间服务器需要发送证书(Certificate)给客户端,为此需要知道客户请求的域名(因为不同域名的证书可能是不一样的)。这时有同学要问了,要连接的主机名不就是发起  HTTP 时的 Host 么!这是对 HTTPS 机制的误解,TLS Handshake 发生时 HTTP 交互还没开始,自然 HTTP   头部还没到达服务器。SNI 协议就定义在 RFC 6066 中:

  1. struct { 

  2.     NameType name_type; 

  3.     select (name_type) { 

  4.         case host_name: HostName; 

  5.     } name; 

  6. } ServerName; 

  7. enum { 

  8.     host_name(0), (255) 

  9. } NameType; 

  10. opaque HostName<1..2^16-1>; 

  11. struct { 

  12.     ServerName server_name_list<1..2^16-1> 

  13. } ServerNameList;


我们看本文刚开始的例子,第4行发往 github.com 的 ClientHello 中的 SNI Extension 字段:

  • Extension Header     ||            Extension Payload (SNI) 

  • --------------------------------------------------------------------------------------------------- 

  • ExtensionType Length || PayloadLength Type      ServerLength ServerName 

  • --------------------------------------------------------------------------------------------------- 

  • 00 00         00 0f  00 0d            00        00 0a        67 69 74 68 75 62 2e 63 6f 6d 

  • sni(0)        15     || 13            host_name 10           github.com



[
ALPN/NPN
]


ALPN(Application-Layer Protocol Negotiation)也是 TLS 层的扩展,用于协商应用层使用的协议。它的前身是  NPN,最初用于支持 Google SPDY 协议(现已标准化为 HTTP/2)。 TLS 客户端和服务器版本的问题,导致 SPDY->HTTP/2 和  NPN -> ALPN 的切换过程引发了不少阵痛:

  • The day Google Chrome disables HTTP/2

  • 从启用 HTTP/2 导致网站无法访问说起

因此 以标准先行的方式来推进 Web 基础设施 已成为今日 Web 平台的共识。这里我们不提那些仍然在进行作坊式生产的(类)浏览器厂商,任何阻挡 Web  平台发展的实现(甚至标准,试看 Xhtml, OSI…)迟早会被淘汰。

言归正传,ALPN 定义在 RFC 7301 - Transport Layer Security (TLS) Application-Layer  Protocol Negotiation Extension,

  1. enum { 

  2.     application_layer_protocol_negotiation(16), (65535) 

  3. } ExtensionType; 

  4. opaque ProtocolName<1..2^8-1>; 

  5. struct { 

  6.     ProtocolName protocol_name_list<2..2^16-1> 

  7. } ProtocolNameList; 



我们看本文刚开始的例子,第4行发往 github.com 的 ClientHello 中的 ALPN Extension 字段:

  1. Extension Header     ||            Extention Payload (ALPN) 

  2. --------------------------------------------------------------------------------------------------- 

  3. ExtensionType Length || PayloadLength StringLength Protocol StringLength Protocol 

  4. --------------------------------------------------------------------------------------------------- 

  5. 00 10         00 0e  00 0c            02           68 32    08           68 74 74 70 2f 31 2e 31 

  6. alpn(16)      14     || 12            2            h2       8            http/1.1 

Extention 的消息体包含多个字符串(protocol_name_list),表示客户端支持的所有应用层协议。上面的例子中有 h2 和  http/1.1 两个,支持 SPDY 的客户端这里会多一个 spdy/2。服务器给出的 ServerHello 中需要选择其中之一,本文的例子中  ServerHello 的 ALPN 字段为:

  1. 00 10 00 0b 00 09 08 68 74 74 70 2f 31 2e 31 

  2.                      h  t  t  p  /  1  .  1 


这样 Server 和 Client 就利用 ALPN 协议达成了共识,将会在握手结束后使用 HTTP/1.1 协议进行通信。



[
参考和致谢
]


从 HTTPS 的关键一层 TLS 开始,介绍了一个典型的 HTTPS 交互过程。结合抓包给出的字节序列,依次介绍了 TLS、SNI、ALPN  等协议原理和主要内容。



以上是关于HTTPS那些协议:TLS, SSL, SNI, ALPN, NPN的主要内容,如果未能解决你的问题,请参考以下文章

nginx和SNI那些事

Azure w/TLS/SNI 上的 .net httpclient:请求被中止:无法创建 SSL/TLS 安全通道

JAVA 6 不支持 SNI,还有其他方法可以通过 TLS 验证和接受 SSL 证书吗?

SNI: 实现多域名虚拟主机的SSL/TLS认证

SNI: 实现多域名虚拟主机的SSL/TLS认证

SSL/TLS协议原理解读