Nginx功能篇13—https

概述

本章,您将学习到关于 https 的相关知识。

前面在 Apache httpd 中介绍过三部分的内容:

  • 第一部分 - https 的基础知识
  • 第二部分 - 手动模拟出 SSL 证书
  • 第三部分 - 在 Apache httpd 中进行配置

要学习第一部分和第二部分的内容,参阅 这里这里

本章只说明如何在 Nginx 中配置 https 的相关内容。

实际情况下的 SSL 证书

在实际的生产情况下,当我们向证书品牌商购买 SSL 证书后,可在网页的控制台中手动下载相关文件,包括:

  • 私钥文件 - 常以 .key 后缀结尾的文件
  • 证书文件 - 常以 .crt 后缀结尾的文件
  • 证书链文件 - 常以 .crt 后缀结尾的文件,文件名中常包含 chain 或 root 等单词

Q:为什么还要有一个证书链文件?

CA 机构通常不会直接使用根证书的私钥对用户的证书进行签发,这是因为:

  • 安全风险极高 - 如果把根证书的私钥拿出来每天给成千上万的用户签名,若根证书私钥泄露,所有签发的证书全部作废,整个信任体系直接崩塌
  • 难以维护 - 根证书的变更或轮换或吊销需要全球所有的操作系统和浏览器更新,成本巨大

为了解决上面的问题,CA 机构采用分层签发模式,即 "根证书" -> "中间证书" -> "用户的签发证书" 这样的层级结构。根证书的私钥被离线存储在最高安全级别的硬件加密模块中,极少使用。

浏览器仅内置根证书,并不预置中间证书,因此在 Web 服务器中必须配置证书链(中间证书),用以向浏览器展示完整的信任路径(Trust Path),即 "根证书" <---> "中间证书" <---> "用户的签发证书"。若 Web 服务器缺少证书链的配置,将导致浏览器因无完整的信任链而出现拒绝连接的情况。

日常混淆
由于大多数人接触最多的是 Web https,因此日常交流过程会将 "CA 证书" 等同于 "SSL 证书",但严格来说没有 "CA 证书" 这个术语或概念。一方面,CA 机构有自己的证书,被称为 **根证书** 或 **中间 CA 证书**;另外一方面,申请者获得的签名证书更加标准的表述是 「CA 机构签发的证书」。所以,当有非从业人员人提到 "CA 证书" 时,你需要清楚它到底是指 CA 自己的证书还是 CA 机构签发的证书。

说明
CA 不仅可以给 Web 服务器颁发证书,软件代码的签名证书、邮件的签名证书、文档的签名证书等都需要 CA 这个机构进行签发

相关指令

证书以及私钥相关的指令:

  • ssl_certificate 指令- 指令参数为一个 PEM 格式的完整证书链文件,该文件内容必须按照以下顺序包含:

    • 证书文件的内容 - CA 机构给你域名签发的文件
    • 证书链文件的内容

    可以使用 cat 命令进行内容合并,如:

    Shell > cat your_domain.crt root_bundle.crt > fullchain.pem
  • ssl_certificate_key 指令 - 指定签发证书对应的私钥文件

安全相关指令:

  • ssl_protocols 指令 - 启用特定的协议,语法为 ssl_protocols [SSLv2] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2] [TLSv1.3];,默认为 ssl_protocols TLSv1.2 TLSv1.3;

  • ssl_ciphers 指令 - 在 SSL 握手期间选择协商的加密套件,加密套件用英语冒号进行分隔,优先级按照从左到右排列,默认为 ssl_ciphers HIGH:!aNULL:!MD5;。可配置的加密套件可通过命令 openssl ciphers 进行查询

    Shell > openssl ciphers
  • ssl_prefer_server_ciphers 指令 - 指定在使用 SSLv3 和 TLS 协议时,是否优先使用服务器加密套件而非客户端加密套件

性能优化相关指令:

  • ssl_session_cache - 存储之前建立过的 SSL/TLS 握手会话信息,使后续的客户端可以复用这些连接会话参数,跳过耗时的完整握手,减少耗时并提高并发性能。语法为 ssl_session_cache off | none | [builtin[:size]] [shared:name:size];,示例配置 ssl_session_cache shared:SSL:10m; 表示所有 worker 进程共享的缓存,在实际情况下可存储约 ‌20000 - 3000‌0 个会话( 1 兆字节大约可存储 2000 - 3000 个会话)

  • ssl_session_timeout - 服务器端 "记住" 某个 SSL/TLS 握手会话的最长时间,通常都设置为 10 分钟或 15 分钟

  • ssl_stapling 指令 - 启用或禁用 ‌OCSP Stapling‌(OCSP 装订)功能。

    • 传统模式 - 当浏览器在 SSL/TLS 握手后,需要单独向 CA 机构的 OCSP 服务器发起请求,查询证书是否被吊销。这会增加额外的网络延迟(通常 150-300ms),且暴露用户访问隐私
    • 装订模式 - Nginx 服务器会定期主动向 CA 的 OCSP 服务器查询证书状态,并将获取到的、带有时间戳和签名的 OCSP 响应 "装订" 在 TLS 握手的 ServerHello 消息中发送给客户端,降低 https 的加载延迟,提升用户体验
  • ssl_stapling_verify 指令 - 是否对从 CA 获取的 OCSP 响应进行‌签名验证‌

  • resolver 指令 - 配置 Nginx 内部使用的 ‌DNS,主要是配合 ‌OCSP Stapling‌

  • resolver_timeout 指令 - 设置 Nginx 进行单次 DNS 查询的‌超时等待时间上限,通常设置为 3s 或 5s

生产环境中比较标准的 https 示例配置:

user  nginx;
worker_processes  4;

error_log  logs/error.log  error;

pid        logs/nginx.pid;

worker_rlimit_nofile 7400;

events {
    use epoll;
    worker_connections  1024;
    multi_accept on;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    sendfile       on;
    tcp_nopush     on;

    # 长连接的超时时间
    keepalive_timeout  30;

    # 隐藏响应头的版本信息
    server_tokens off;

    # 压缩响应相关
    gzip on;
    gzip_vary on;
    gzip_buffers 32 4K;
    gzip_comp_level 5;
    gzip_types text/plain text/css text/xml application/json application/javascript application/xml application/xhtml+xml image/svg+xml application/x-font-ttf application/x-font-opentype application/vnd.ms-fontobject font/woff;
    gzip_min_length 256;

    # 80 端口的 server 上下文
    server {
        listen 192.168.100.20:80;
        server_name www.my-tests.com;

        return 301 https://www.my-tests.com$request_uri;
    }

    # 443 端口的 server 上下文
    server {
        # 443 端口的 server 上下文中,listen 指令的指令参数通常都有 ssl 和 http2 
        listen 192.168.100.20:443 ssl http2 backlog=8000 reuseport;
        server_name www.my-tests.com;

        ssl_certificate /usr/local/nginx/ssl/fullchain.pem;
        ssl_certificate_key /usr/local/nginx/ssl/my_privkey.key;

        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers on;
        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_session_cache shared:SSL:10m;
        ssl_session_timeout 15m;
        ssl_stapling on;
        ssl_stapling_verify on;
        resolver 8.8.8.8 8.8.4.4 valid=300s;
        resolver_timeout 5s;

        ...

        location / {
            ...
        }
        ...
    }
}

此处的 https 示例配置不能包含所有的业务使用场景,使用者应该根据实际情况酌情增加或减少相关的配置。

校验加密套件

校验主配置文件 nginx.conf 中的加密套件:

Shell > openssl ciphers -v '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'
TLS_AES_256_GCM_SHA384  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(256) Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any      Au=any  Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(128) Mac=AEAD
TLS_AES_128_CCM_SHA256  TLSv1.3 Kx=any      Au=any  Enc=AESCCM(128) Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(128) Mac=AEAD
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
ECDHE-RSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH     Au=RSA  Enc=CHACHA20/POLY1305(256) Mac=AEAD
DHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=DH       Au=RSA  Enc=AESGCM(128) Mac=AEAD
DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH       Au=RSA  Enc=AESGCM(256) Mac=AEAD

输出中的每一行代表一个套件,其由以下信息组成:

  • 套件名称 - 如 TLS_AES_256_GCM_SHA384,你在 nginx.conf 中配置的就使用这个套件名称
  • SSL/TLS 版本 - 套件支持的最低 TLS 版本
  • 密钥交换(Kx) - 客户端与服务器协商会话密钥所用的算法
  • 身份认证(Au) - 签发证书用于身份验证的算法
  • 对称加密(Enc) - 实际数据传输时的对称加密算法及密钥长度
  • 消息摘要(Mac) - 完整性校验算法

在前面的 Apache httpd 中介绍过 https 的底层原理 —— https 的底层大量使用了非对称加密 + 对称加密 + 哈希算法。

  1. 非对称加密

    证书的签名就是利用非对称加密实现的,另外在握手阶段,会用非对称加密完成预主密钥的 "协商" 或其他密钥材料的 "协商",并 "派生" 出会话密钥。

  2. 对称加密

    握手完成后,后续所有通信数据‌都用对称加密传输,常见算法有 AES-128、AES-256、ChaCha20 等。

  3. 哈希算法

    主要用来验证数据的完整性,防止数据被篡改。另外,证书的签名验证也依赖哈希算法。

┌─────────────┐
│   握手阶段    │  非对称加密(交换密钥)+ 哈希(验证身份)
├─────────────┤
│   通信阶段    │  对称加密(加密数据)+ 哈希/HMAC(防篡改)
└─────────────┘
Avatar photo

关于 陸風睿

GNU/Linux 从业者、开源爱好者、技术钻研者,撰写文档既是兴趣也是工作内容之一。Q - "281957576";WeChat - "jiulongxiaotianci",Github - https://github.com/jimcat8
用一杯咖啡支持我们,我们的每一篇[文档]都经过实际操作和精心打磨,而不是简单地从网上复制粘贴。期间投入了大量心血,只为能够真正帮助到您。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇