浅谈 HTTPS

浅谈 HTTPS

相信你们都会注意到不少网站的地址栏上会出现一个绿色的小锁,好比:算法

若是地址栏中出现了这样子的绿色小锁,则表示当前页面是经过 HTTPS 传递的,只要证书是正确的,那么目前来讲能够保证网页内容没有被篡改以及即便第三者截取到了通讯内容也没法从密文得到明文。数组

什么是 HTTPS?

HTTPS 相似于 HTTP 协议的“安全版”,其全称为超文本传输安全协议(英文:HyperText Transfer Protocol Secure,缩写 HTTPS),如下引用自维基百科:浏览器

超文本传输安全协议是一种透过计算机网络进行安全通信的传输协议。HTTPS 经由 HTTP 进行通信,但利用 SSL/TLS 来加密封包。HTTPS 开发的主要目的,是提供对网站服务器的身份认证,保护交换资料的隐私与完整性。这个协议由网景公司(Netscape)在1994年首次提出,随后扩展到互联网上。

HTTPS 的用途就是在不安全的网络上创建安全的信道,用于传输敏感数据(好比信用卡号、密码等)或者用于保护互联网帐户不被盗取、保证网页数据的正确性等。安全

HTTPS 有什么用?

经过 HTTP 协议传输的数据就像 Tom 给 Jerry 写信,Tom 把写好的信直接交给了邮递员,信封没有密封甚至直接没有信封,邮递员能够随意查看 Tom 给 Jerry 的信件、修改信件里的内容甚至冒充 Tom 与 Jerry 进行通讯。服务器

这明显是不安全的。网络

Tom 为了避免让邮递员偷看他给 Jerry 的信件并确保本身的信件不会被替换,决定在信的最后附上本身的签名,并在信封上加上火漆印章(一旦信件被私自拆阅则印章就会损毁),这时,若是 Tom 再给 Jerry 写信,Jerry 只须要在收到信件的时候检查信封上的火漆印章和信件最后的签名,就能够确保收到的信件没有被邮递员拆阅或者替换过。curl

在这个例子中,Tom 和 Jerry 分别表明客户端和服务器(或者服务器与服务器、客户端与客户端),邮递员至关于不安全的网络信道(好比包含 ISP、代理服务器等),而信件就至关于 HTTP 请求中的内容。Tom 签名及盖火漆印章的过程至关于加密,验证签名和火漆印章完整性的时候就至关于身份验证和解密。函数

在实际中,不使用 HTTPS 的风险不只是数据被随时监视,无良的 ISP 可能还会给网页上加上广告,甚至能够随意增删经过 HTTP 传输的网站代码,这很是危险。而 HTTPS 能够避免这些风险。网站

HTTPS 链接的握手过程

咱们可使用 curl 命令来简略查看创建 HTTPS 时的握手过程,在命令行中执行:curl -v -I -L https://ymfe.org加密

能获得以下的输出:

curl_https_ymfe.org

简单说明一下链接的创建过程:

# 表示创建了和 ymfe.org 服务器 443 端口的链接。
Connected to ymfe.org (123.56.155.201) port 443 (#0) 

# 客户端发出 client_hello 消息。
TLSv1.2 (OUT), TLS handshake, Client hello (1): 

# 服务器发出 server_hello 消息。
TLSv1.2 (IN), TLS handshake, Server hello (2): 

# 服务器发出 certificate 消息。
TLSv1.2 (IN), TLS handshake, Certificate (11): 

# 服务器发出 server_key_exchange 消息。
TLSv1.2 (IN), TLS handshake, Server key exchange (12): 

# 服务器发出 server_done 消息。
TLSv1.2 (IN), TLS handshake, Server finished (14): 

# 客户端发出 client_key_exchange 消息。
TLSv1.2 (OUT), TLS handshake, Client key exchange (16): 

# 客户端发出加密后的 client_hello 消息。
TLSv1.2 (OUT), TLS change cipher, Client hello (1): 

# 客户端发出 hello_done 消息。
TLSv1.2 (OUT), TLS handshake, Finished (20): 

# 服务器将加密后的 client_hello 消息发回。
TLSv1.2 (IN), TLS change cipher, Client hello (1): 

# 握手结束。
TLSv1.2 (IN), TLS handshake, Finished (20): 

# SSL 链接采用 ECDHE-RSA-AES256-GCM-SHA384 密码套件。
# ECDHE 表示密钥交换方法采用椭圆曲线迪菲-赫尔曼交换方法
# RSA 表示密钥交换中使用的签名方式
# AES-256-GCM 表示的是对称加密算法
# SHA-384 表示的是内容完整性校验使用的哈希算法
SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 

# 以后的几行包含了证书的内容,包括有效时间、经常使用名、证书签发机构等。
Server certificate: 
      # Common Name 为 ymfe.org
    subject: CN=ymfe.org
      # 在此时间以前无效
    start date: Aug 31 05:50:00 2017 GMT
      # 在此时间以后无效
    expire date: Nov 29 05:50:00 2017 GMT
      # 域名和证书的域名匹配
    subjectAltName: host "ymfe.org" matched cert's "ymfe.org"
      # 签发者是 Let's Encrypt
    issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3

握手的详细步骤

client_hello

这一步中,浏览器会向服务器发出创建 HTTPS 的请求,在请求中,浏览器会带上一些创建链接的必要信息(注意:这一步的信息全都是明文的),包括:

  1. 版本。客户端支持的最高的 TLS 协议版本从高到低依次为:TLS v1.2, TLS v1.1, TLS v1.0, SSL v3, SSL v2。其中低于 TLS v1.0 的版本基本再也不使用,由于 SSL v3 和 SSL v2 都存在漏洞,Google 和 Mozilla 已明确禁用 SSL 协议。
  2. 密码套件。按优先级降序排列的、客户端支持的加密套件列表。每一个加密套件会各包含一个认证算法(用于身份验证)、密钥交换算法(用于协商密钥)、对称加密算法(用于消息加密)和信息摘要算法(用于完整性校验)。
  3. 压缩方法。客户端支持的用于压缩消息、下降传输体积的压缩算法列表。
  4. 随机数。一个由客户端生成的随机数,使用 32 位时间戳和一个安全随机数生成器生成的 28 字节随机数组成。这个随机数用于后续 Master Key 的生成,并防止重放攻击。
  5. 会话标识。一个变长的会话标志。非 0 值意味着客户端但愿更新当前已存在的链接的参数或者为此链接建立一个新的链接。0 值表示客户端想在新会话上建立一个新链接。
  6. 扩展字段。包含一些其余的相关参数(好比 SNI)。

server_hello

客户端在发出 client_hello 消息以后,会等待服务器返回 server_hello 消息,包含和 client_hello 相同的参数。通常来讲,参数结构以下:

  1. 版本。包含客户端支持的最低版本和服务器支持的最高版本。
  2. 随机数。由服务器生成的不一样于客户端在 client_hello 中发来的随机数的另外一个独立的随机数。
  3. 会话标识。若是客户端发送的会话标识不为 0,服务器会使用与客户端发送的一致的会话标识,不然返回的是服务器生成的一个新的会话标识。
  4. 密码套件。包含了服务器从客户端发来的密码套件列表中选择出的将要使用的密码套件。
  5. 压缩方法。包含了服务器从客户端发来的压缩方法列表中选择出的将要使用的压缩方法。

(certificate) (+ server_key_exchange) (+ certificate_request) + server_hello _done

一般来讲,服务器会在 certificate 消息中发送其自身的证书供客户端进行验证,这个消息包含一个或一组 X. 509 证书。若是采用的是固定 Diffie-Hellman 方法(更多关于 Diffie-Hellman 的内容请查看维基百科上的词条 Diffie-Hellman),此 certificate 消息将使用服务器 Diffie-Hellman 公钥参数做为服务器的密钥交换消息。有一种密钥交换方法——匿名 Diffie-Hellman 方法,不须要 certificate 消息。该算法使用基本的 Diffie-Hellman 算法,在向对方发送其 Diffie-Hellman 公钥参数时,不进行认证(由于没有认证,因此这种方法容易受到中间人攻击)。

接着,除了两种状况:(1) 服务器发送了带有固定 Diffie-Hellman 参数的证书;(2) 使用 RSA 密钥交换;不须要发送 server_key_exchange 消息,其他状况服务器均会发送 server_key_exchange 消息,用以向客户端发送以后用以生成密钥的各项参数。该消息的内容根据密钥交换算法不一样而不一样,具体内容不在本文讨论之列。该项参数做为 server_key_exchange 消息的第一项值。

而后,服务器将对消息使用散列函数(根据不一样签名算法选择不一样的散列函数,例如 MD5 或者 SHA-1 等)对客户端发来的随机数、服务器生成的随机数以及 server_key_exchange 消息中的各项参数进行求值并使用服务器的私钥进行签名。该值做为 server_key_exchange 消息中的第二项值。

若是服务器须要验证客户端的身份(即双向认证),则会发送 certificate_request 消息,请求客户端发送其自身的证书。

最后,服务器发送 server_hello_done 消息,代表服务器的 hello 相关的消息结束。在发送此消息以后,服务器会等待客户端应答,该消息没有参数。

(certificate) + client_key_change (+ certificate_verify)

客户端在收到服务器发来的 server_hello_done 消息以后,会验证服务器提供的证书是否合法,并检查 server_hello 的各项参数。若是验证经过,则客户端会向服务器发送一条或多条消息。

若是服务器发送了 certificate_request 消息,且客户端有合适的证书,则客户端会发送一条 certificate 消息,不然会发送一个“无证书警报”。

而后客户端会发送 client_key_exchange 消息,其内容取决于密钥交换的类型:

  1. RSA:客户端生成 48 字节的 PreMaster Key,并使用服务器证书中的公钥或者服务器密钥交换消息中的临时 RSA 密钥加密。这个密钥会被用于以后的 Master Key 的计算。
  2. 瞬时或匿名 Diffie-Hellman: 发送客户端的 Diffie-Hellman 公钥参数。
  3. 固定 Diffie-Hellman: 因为证书消息中包括 Diffie-Hellman 公钥参数,因此该消息为空。

最后,若是客户端具备证书且证书具有签名能力(即除了带固定 Diffie-Hellman 参数外的全部证书),能够发送一个 certificate_verify 消息来提供对客户端证书的精确认证。

change_cipher_spec + finished

通过以上步骤,客户端和服务器已经能够经过获得的消息计算出 Master Key 了。从如今开始,客户端和服务器都将开始使用协商好的加密算法、密钥进行通讯,在正式传递消息以前会计算 Master Key 及 Master Key 和以前握手过程当中收到的全部信息的 hash,并经过协商好的加密算法使用 Master Key 加密,做为 change_cipher_spec 消息的内容,接着发送 finished 消息。服务器在收到客户端发来的 change_cipher_specfinished 消息以后,也会计算 Master Key 并使用协商好的加密算法和 Master Key 计算 Master Key 和以前握手过程当中收到的全部信息的 hash,发回给客户端用以验证。至此,握手阶段结束,以后就能够交换应用层的内容了。

如何加密应用层内容

细心的读者可能发现,在创建链接的过程当中,交换的仅仅是密钥而不是内容,为何这么复杂的过程仅仅交换了密钥呢?

对称加密和非对称加密

经常使用的加密方式分为两种:

  • 对称加密:加密和解密使用的是相同的密钥。
  • 非对称加密:加密和解密使用的不是相同的密钥,而是一对密钥对,分别称为公钥私钥

对称加密最大的特色就是通讯双方都须要知道加密密钥,这对于互联网上的服务器和客户端来讲,在事先没有创建安全信道的状况下安全地传送密钥几乎是不可能的。不过相较于非对称加密来讲,对称加密的优势就是快。

非对称加密最大的特色就是通讯双方只须要知道密钥对中的一个,并且使用公钥加密的内容只能经过私钥解密,使用私钥加密的内容只能经过公钥解密。对于一个实体来讲,公钥能够公开给任何人,只须要保证自身的私钥的安全,就能够保证其与另外一个实体的通讯内容不会被第三者窃取。

HTTPS 用了哪一种加密方法?

在 HTTPS 中,对称加密和非对称加密都用到了。非对称加密能够在不安全的信道上传递秘密内容,可是因为一般使用的非对称加密方法相较于对称加密算法慢不少,所以在 HTTPS 中仅使用非对称加密算法交换对称密钥,交换密钥以后的通讯内容均使用对称加密算法加密和解密,这样既能够保证密钥的安全也能够保证内容的加解密速度,这对于移动端设备来讲相当重要。

扩展阅读

中间人攻击

中间人攻击(Man In The Middle Attack,简称 MITM),是指攻击者与本来通讯的两个实体分别创建通讯,并交换攻击者所收到的数据,让本来通讯的两个实体误觉得本身在一条加密的信道中和对方直接对话,但其实整个对话过程都直接受到攻击者的控制,攻击者能够随意增长、删除、修改通讯的内容。通常来讲,加密协议都会加入一些特殊的方法来实现通讯双方的互相认证,以免中间人攻击。好比 HTTPS 中就使用证书机制来防止中间人攻击。

以前提到匿名 Diffie-Hellman 方法易受中间人攻击,就是由于其不对秘密内容(即 Diffie-Hellman 公钥参数)进行签名认证致使的。在这个过程当中,服务器向客户端发送的公钥参数若是被攻击者截获并替换为本身的公钥参数,那么攻击者就能够假装成服务器和客户端分别和客户端和服务器进行对话,并且能够彻底控制通讯的内容。

SNI

当进行 SSL/TLS 握手时,服务器会提供自身的证书给客户端以供客户端验证。可是若是一台服务器上托管了多个 HTTPS 站点,那么服务器提供的证书可能就是错误的。而对于 SSL/TLS 握手链接来讲,服务器名称不匹配会致使客户端断开链接,由于服务器名称不匹配代表可能有人正在进行中间人攻击。

一张证书中包含多个主机名是能够的,在以前提到的 curl -v -I -L https://ymfe.org 命令中出现了一个叫作 subjectAltName 的字段,这个字段就是用于指定多个域名的,在 common namesubjectAltName 中还可使用通配符。

一台服务器托管多个站点是很是常见的。在被托管的站点中,它们多是同一个域名下的子域名,也可能彻底不是同一个域名。若是多个站点都用同一张证书的话,那么服务器须要知道全部被托管的站点的域名,维护一个域名列表,这在不少状况下是不切实际的。而若是为每一个 HTTPS 服务器都分配一个独立的 IP 的话,不但会增长成本,还会恶化 IPv4 地址的枯竭状况。

基于名称的虚拟主机可让多个 DNS 主机名指向同一个服务器。在客户端发起请求的时候,会在 HTTP 头部添加正在请求的主机名称,服务器根据这个主机名称来提供不一样的服务。而 HTTPS 中,在创建握手以前是不会发送任何 HTTP 头部的,也就没法获取客户端正在请求的主机名称了。所以,没法使用 HTTP 头部来决定给客户端提供哪张证书。

SNI(Server Name Indication,服务器名称指示)是一个扩展的 TLS 协议。这个协议容许客户端在创建 HTTPS 握手时告知服务器它正在链接的服务器的名称。这就容许服务器根据客户端在握手消息发来的服务器名称来提供正确的 HTTPS 证书,避免由于证书错误致使握手失败。

相关文章
相关标签/搜索