HTTPS握手

从一份nginx配置谈起

server {
listen 443 ssl http2;
listen [::]:443 ssl http2;

ssl_certificate /path/to/signed_cert_plus_intermediates;
ssl_certificate_key /path/to/private_key;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
ssl_session_tickets off;

# curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam.pem
ssl_dhparam /path/to/dhparam.pem;

# intermediate configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;

# HSTS (ngx_http_headers_module is required) (63072000 seconds)
add_header Strict-Transport-Security "max-age=63072000" always;

# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;

# verify chain of trust of OCSP response using Root CA and Intermediate certs
ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates;

# replace with the IP address of your resolver
resolver 127.0.0.1;
}
  1. ssl_protocols

    当前流行的https加密协议包括SSL3.0 TLS1.0 TLS2.0 TLS3.0
    TLS(Transport Layer Security 传输层安全协议)是SSL(Secure Sockets Layer 安全套接字)的替换协议。目前协议状态如下

    协议 发布时间 状态
    SSL 1.0 未发布 安全问题未发布
    SSL 2.0 1995年 已于2011年弃用
    SSL 3.0 1996年 已于2015年弃用
    TLS 1.0 1999年 计划于2020年弃用
    TLS 1.1 2006年 计划于2020年弃用
    TLS 1.2 1999年 主流协议
    TLS 1.3 2008年 主流浏览器已经支持

    HTTPS 加密流程采用那种协议需要客户端与服务器协商,考虑到客户端版本滞后的特性,服务器必须支持多种协议,比如上面这份nginx的配置来自Mozilla建议支持TLS1.2、TLS1.3。

    Mozilla 这份配置的兼容性 Firefox 27, Android 4.4.2, Chrome 31, Edge, IE 11 on Windows 7, Java 8u31, OpenSSL 1.0.1, Opera 20, and Safari 9
    从上面我们已知的HTTPS加密支持TLS、SSL,那么这两种协议差异在哪里?我们该如何选择呢?

  2. TLS 握手

    对于现代短连接服务端设置一般来说支持TLS1.2 TLS1.3 没有任何问题,探究细节客户端与服务端怎么选择使用那个版本的协议呢?
    这个流程为TLS握手的大致过程,早期的SSL握手过程也差不多,只是更简单点。

    [图片来自cloudfare]

    参照真实测试了解一下TLS通信过程

    ➜  ~ curl -I  -v https://notes.icool.io
    * Trying 47.240.72.238...
    * TCP_NODELAY set
    * Connected to notes.icool.io (47.240.72.238) port 443 (#0)
    * ALPN, offering h2
    * ALPN, offering http/1.1
    * successfully set certificate verify locations:
    * CAfile: /etc/ssl/cert.pem
    CApath: none
    * TLSv1.2 (OUT), TLS handshake, Client hello (1):
    * TLSv1.2 (IN), TLS handshake, Server hello (2):
    * TLSv1.2 (IN), TLS handshake, Certificate (11):
    * TLSv1.2 (IN), TLS handshake, Server key exchange (12):
    * TLSv1.2 (IN), TLS handshake, Server finished (14):
    * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
    * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (OUT), TLS handshake, Finished (20):
    * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (IN), TLS handshake, Finished (20):
    * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
    * ALPN, server accepted to use h2
    * Server certificate:
    * subject: CN=notes.icool.io
    * start date: Dec 23 08:24:36 2019 GMT
    * expire date: Mar 22 08:24:36 2020 GMT
    * subjectAltName: host "notes.icool.io" matched cert's "notes.icool.io"
    * issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
    * SSL certificate verify ok.
    * Using HTTP2, server supports multi-use
    * Connection state changed (HTTP/2 confirmed)
    * Copying HTTP/2 data in stream buffer to connection buffer after

    过程解析(TLS1.2为例)

    1.密钥交换和密钥协商(1)

    • 客户端发送 ClientHello

      客户端随机数(会话密钥); S1.0 TLS1.1 TLS 1.2;加密套件,比如 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256; 压缩算法;SessionId (会话恢复时使用)

    • 服务端发送 ServerHello 到客户端(2)

      服务端随机数;服务端选定的协议版本; 加密方法
      2.服务端发送证书(11)
      客户端收到证书会使用系统预存CA证书校验证书合法性、过期时间、证书状态等信息

    3.服务端发送公钥交换(12)

    服务器公钥; 签名(使用RSA私钥签名)

    4.服务端握手完成(14)

    5.客户端公钥交换(16)

    #客户端生成主密钥,使用公钥加密后发送服务端
    master_secret = PRF(pre_master_secret, "master secret",ClientHello.random + ServerHello.random)

    6.握手完成

    以本次握手为例,稍后通信将使用AES256作为对称加密算法,主密钥做密钥加密通信

  3. ssl_ciphers

    不同服务器加密套件选择,建议使用Mozilla建议,
    https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=intermediate&openssl=1.1.1d&guideline=5.4

  4. HSTS( HTTP严格传输安全)

    HSTS可以用来抵御SSL剥离攻击,要求浏览器总是使用https访问网站。

  5. OCSP

    握手阶段我们提到了,客户端获取证书后需要使用预制的CA校验证书,但这里存在一定风险 – 证书吊销,服务器通过配置ssl_stapling=on通知浏览器做证书在线验证。