服务器搭建记录 · 配置HTTPS

前言

使用 HTTPS 的原因是什么?摘自Cloudflare

浏览器将非 HTTPS 网站标记为“不安全”,这只是保护网站的众多理由之一。

HTTPS可以部署在后端服务器上,也可以部署在CDN上。这里主要是介绍如何配置在服务器上。

在开始以下内容之前,你需要一个SSL证书,也可以看我的这篇文章:服务器搭建记录 · 使用ACME.sh生成并自动续签免费证书来使用acme.sh生成一个免费证书。

之后,你可以使用moz://a SSL Configuration Generator来生成一个通用的SSL配置。

如果嫌麻烦,也可以使用我的配置,证书路径为/etc/nginx/cert/,此配置XP系统无法访问:

server {
    listen 443 ssl;
    http2 on;
    server_name example.com www.example.com;

    ssl_certificate     /etc/nginx/cert/cert.pem;
    ssl_certificate_key /etc/nginx/cert/cert.key;

    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:10m;
    ssl_dhparam /etc/nginx/cert/dhparam.pem; #需自行生成
    add_header X-XSS-Protection 1;
    add_header X-Frame-Options SAMEORIGIN;

    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:DHE-RSA-CHACHA20-POLY1305;
    ssl_prefer_server_ciphers off;

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; #注意已开启HSTS
    add_header Public-Key-Pins 'pin-sha256="base64"; pin-sha256="base64"; max-age=2592000; includeSubDomains'; #需自行计算base64并替换此处
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 223.5.5.5 valid=60s;
    resolver_timeout 3s;

    location / {
    root /usr/share/nginx/home;
        index index.html index.htm;
    }
}
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri; 
}

在一切都配置完之后,可以使用MySSLSSL Labs来检测你的网站是否配置好了HTTPS。

参数详解

ssl_protocols

指定服务器接受连接的SSL/TLS协议版本。TLS协议版本包括TLS v1.0(已禁用)、TLS v1.1、TLS v1.2和TLS v1.3。TLS协议版本越高,HTTPS通信的安全性越高,但是相较于低版本TLS协议,高版本TLS协议对浏览器的兼容性较差。

SSL协议

如果要适配IE6,那么SSL协议就必须支持SSL3,因为IE6仅支持SSL2SSL3SSL2被明确说明为不安全,SSL3上有著名的POODLE漏洞,所以只能使用RC4系列的加密套件。

ssl_ciphers

密码套件:SSL/TLS涉及多种密码学算法,选择安全、且性能高的密码套件非常重要。但安全和性能是反相关的,需要平衡这两者。下面是选择建议:

  • 密钥协商算法
    • ECDHE:优先选择ECDHE作为密钥协商算法,椭圆曲线选择x25519,其次P-256
    • DHE:长度选择2048bit
  • 身份验证算法
    • ECDSA:优先选择ECDSA,椭圆曲线选择x25519,其次P-256
    • RSA:长度选择2048bit
  • 加密算法和分组模式
    • AES_128_GCM:长度是128bit
    • CHACHA20_POLY1305
    • AES_256_GCM:长度是256bit

TLSv1.2的密码套件非常多,但建议按照上面的进行选择,按上面的组合后:

  • ECDHE-ECDSA-AES128-GCM-SHA256
  • ECDHE-ECDSA-CHACHA20-POLY1305
  • ECDHE-RSA-AES128-GCM-SHA256
  • ECDHE-RSA-CHACHA20-POLY1305
  • ECDHE-ECDSA-AES256-GCM-SHA384
  • ECDHE-RSA-AES256-GCM-SHA384
  • DHE-RSA-AES128-GCM-SHA256
  • DHE-RSA-AES256-GCM-SHA384

TLSv1.3废除了许多不安全的密码套件,只保留了以下5种密码套件

  • TLS_AES_128_GCM_SHA256
  • TLS_CHACHA20_POLY1305_SHA256
  • TLS_AES_256_GCM_SHA384
  • TLS_AES_128_CCM_SHA256
  • TLS_AES_128_CCM_8_SHA256

TLSv1.3中保留的算法

  • 密钥交换算法只保留:ECDHE, DHE
  • 椭圆曲线保留:x25519,P-256等5种
  • 加密算法只保留:AES,ChaCha20
  • 分组模式:GCM,Poly1305,CCM
  • 摘要只保留:SHA256,SHA384

废除密钥交换算法RSA、DH的原因是,这两种算法不具备前向安全性(FS)

  • RSA:一旦密钥泄露,就可以破解出共享密钥,从而解密密文。
  • DH:静态DH,使用相同的公钥和私钥来生成Pre-Master,DHE每次连接生成公钥,私钥,一次会话一次密码。

前向安全性(Forward Secrecy):客户端和服务器协商一个永不重用的密钥,并在会话结束时销毁它。服务器上的 RSA 私钥用于客户端和服务器之间的 Diffie-Hellman 密钥交换签名。从 Diffie-Hellman 握手中获取的预主密钥会用于之后的编码。因为预主密钥是特定于客户端和服务器之间建立的某个连接,并且只用在一个限定的时间内,所以称作短暂模式(Ephemeral)。
使用了前向安全性,如果一个攻击者取得了一个服务器的私钥,他是不能解码之前的通讯信息的。这个私钥仅用于 Diffie Hellman 握手签名,并不会泄露预主密钥。Diffie Hellman 算法会确保预主密钥绝不会离开客户端和服务器,而且不能被中间人攻击所拦截。
nginx 依赖于 OpenSSL 给 Diffie-Hellman (DH)的输入参数。不幸的是,这意味着 Diffie-Hellman Ephemeral(DHE)将使用 OpenSSL 的默认设置,包括一个用于密钥交换的1024位密钥。因为我们正在使用2048位证书,DHE 客户端就会使用一个要比非 DHE 客户端更弱的密钥交换。

ssl_prefer_server_ciphers off

选择密码套件时,以服务端ssl_ciphers配置的顺序为准,默认值on。改为off可避免因客户机性能不足而导致的加载缓慢。

ssl_dhparam /etc/nginx/dhparam.pem

若使用DHE密钥协商算法,需要使用下列命令生成并指定DHE Param,要求2048bit

openssl dhparam -out /etc/nginx/dhparam.pem 2048

ssl_ecdh_curve X25519:P-256;

ECC椭圆曲线,默认根据OpenSSL选择

HSTS(HTTP Strict Transport Security)

Strict-Transport-Security是一个HTTP响应头部字段,用来告诉浏览器只能使用HTTPS访问服务器资源。访问HTTPS网站时,若不指定https协议头,仍然会使用http进行请求。通常在服务端会使用301、302进行跳转到https。这样做虽然也可以最终让浏览器通过https访问服务器,但是存在两个问题:首次访问时仍然时http,需要跳转浪费1-RTT的时间。

Nginx配置如下:

add_header Strict-Transport-Security: max-age=<expire-time>[; includeSubDomains][; preload]
  • max-age:有效时间;浏览器记住的有效时间
  • includeSubDomains:是否包含子域名;可选参数
  • preload:是否预加载;可选参数

HSTS Preloading

我们实现了浏览器维持 HTTPS 连接,但是仍然存在一个问题,如果我们是第一次访问该站点呢?那浏览器并不知道该站点的配置,所以也就不知道应该用 HTTPS 去连接,这个问题怎么解决?

HSTS Preload List是一个谷歌维护的列表,现在大部分主流浏览器都支持这个列表,这个列表直接告诉浏览器要用HTTPS访问的站点有哪些,把网站加入列表后,即使是第一次访问,也会使用HTTPS连接。

在提交之前,你需要注意以下几点:

  1. 提供有效的站点证书
  2. 将 HTTP 重定向到 HTTPS
  3. 所有的子域名也都要支持 HTTPS
  4. HSTS 头部配置需要:
    • max-age 需要至少 31536000 秒
    • 必须包含includeSubDomains参数
    • 必须包含preload参数

注意:从列表中删除需要很长时间,如果你之后还会切换回HTTP,需要谨慎考虑。

HTTP/2

即 HTTP 2.0,是下一代的 HTTP 协议,现在只支持 HTTPS 开启。具有以下特点:

  • 彻底的二进制协议
  • 多路复用请求
  • 对请求划分优先级
  • 压缩HTTP头
  • 服务器推送流(即Server Push技术)
  • 保持与HTTP 1.1语义的向后兼容性

HTTP/2是为了优化HTTP而诞生的协议,那么HTTP存在什么问题呢?

HTTP问题1:队首阻塞 HTTP单个TCP连接中,多个请求应答必须按照严格的顺序排队进行。比如服务器接收到多个请求报文,响应报文要按照请求报文发来时的先后顺序依次响应。这会造成队首阻塞问题,即第一个报文响应延迟,其他报文均需等待。为了解决此问题,浏览器通常打开多个TCP连接,但是这会造成服务连接过多,压力大。所以默认浏览器最多打开6个连接。

HTTP/2优化方法: HTTP/2为了兼容HTTP。报文语义上仍然由Header + Body组成,只是将每个请求/应答虚拟成一个Stream。然后将HTTP报文切割成几块,每一块封装成一个二进制帧。一个Stream中的所有二进制帧头部包含相同的Stream ID ,不同Stream中的二进制Stream ID不相同。然后一个TCP连接中多个Stream可以并发请求,服务器也可以并发应答。并且Stream之间相互独立,不存在先后顺序。从而解决了HTTP中队首阻塞的问题。但是一个Stream中的多个二进制帧必须严格按照顺序进行请求/应答。

HTTP问题2:头部字段占用空间大 HTTP报文中有非常多的头部字段,经常会出现一个请求报文中Body非常小,甚至没有,而Header仍然很大,就像大头娃娃。

HTTP/2优化方法: 虽然HTTP中也存在gzip压缩方法,但是该方法只是用来对Body进行压缩的,并没有对头部字段进行压缩。HTTP/2专门针对HTTP中的头部字段设计了HPACK压缩算法。该算法是一个有状态的算法。首先通信双方维护一张静态表,对常用的头部字段进行编号,这些编号称为Index,发送的报文中就只需要带上编号。接收方通过编号查找静态表从而恢复头部字段。由于编号比头部字段小得多,从而起到压缩头部字段的作用。若出现静态表中没有的字段,则会双方动态的将这些字段添加都静态表中。

上 HTTP/2 给我们带来的最直观的体验就是,极大地加快了站点页面的加载速度。

注意:如果在 Chrome51 版本的 Chrome 浏览器中,HTTP/2不生效,检查一下是否支持 ALPN,支持 ALPN 需要开启 OCSP Stapling。

0-RTT

TLSv1.2无论是False Start,Session ID,Session Ticket都只能将TLS握手缩短到1-RTT,而TLSv1.3可以使用更激进的方法,将TLS握手过程缩短为0-RTT。

开启条件TLSv1.3且配置了会话复用Session ID或Session Ticket

OCSP (Online Certificate Status Protocol) Stapling

在线证书状态协议(Online Certificate Status Protocol),简称 OCSP,是一个用于获取 X.509 数字证书撤销状态的网际协议,在 RFC 6960 中定义。OCSP 用于检验证书合法性,查询服务一般由证书所属 CA 提供。OCSP 查询的本质,是一次完整的 HTTP 请求加响应的过程,这中间涵括的 DNS 查询、建立 TCP 连接、Web 端工作等步骤,都将耗费更多时间,使得建立 TLS 花费更多时长。

OCSP存在隐私和性能问题:
1、浏览器直接去请求第三方CA(Certificate Authority, 数字证书认证机构),会暴露网站的访客(CA 机构会知道哪些用户在访问我们的网站);
2、浏览器进行OCSP查询会降低HTTPS性能(访问我们的网站会变慢) OCSP实时查询会增加客户端的性能开销。

OCSP Stapling 技术是对 OCSP协议 的进一步升级。将原本需要客户端实时发起的 OCSP 请求转嫁给服务端。服务器事先模拟浏览器对证书链进行验证,然后将 OCSP 验证结果缓存到本地。这样,当浏览器访问站点时,在握手阶段,可以直接拿到 OCSP 响应结果和证书链,就不需要再向 CA 请求接口,对访问速度有明显提升。

Nginx 中开启 OCSP Stapling

ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /path/to/certs/chained.pem;

如果 ssl_certificate 指定了完整的证书链,则 ssl_trusted_certificate 可省略。

在线校验:此方式需要服务器主动访问证书校验服务器,每次重启时主动请求一次。默认包含在证书中。

resolver 8.8.8.8 223.5.5.5 valid=60s; #主机名与缓存时间
resolver_timeout 2s;#网络超时时间

人工更新:Nginx从文件获取OCSP响应而无需从服务器校验。

ssl_stapling_file /xxx/xxx/stapling_file.ocsp; 

.ocsp文件应采用openssl ocsp命令生成的 DER 格式。

Apache 中开启 OCSP Stapling

在 <VirtualHost></VirtualHost> 中添加:SSLUseStapling on

在 <VirtualHost></VirtualHost> 外添加:SSLStaplingCache shmcb:/tmp/stapling_cache(128000)

TLS Session Resumption(TLS 会话复用):

TLS会话复用指客户端与服务端经过首次握手后,客户端内存中保存了服务端发过来的会话信息,后面的握手过程客户端携带上会话信息,服务端验证会话信息,验证通过直接恢复会话,跳过证书验证、密钥交换等握手过程。

Session ID resumption

Session ID:服务端内存保存各个客户端ID对应的会话信息,只将ID发送给客户端,类似于Session。TLS首次握手时,服务端生成客户端的ID及对应的会话信息,并将该ID发送给客户端。后续握手时,客户端Client Hello中携带ID,服务端通过ID查找内存中是否有该会话信息,找到则直接恢复会话。不再进行后续握手过程。

如果客户端和服务器端都保存了 session keys,我们就可以重用加密的 session。通过给每个连接一个唯一标识,服务端可以知道一个进来的连接是否在之前已经建立过连接,如果在服务器中也存在这个 session 的 key,那么它就能重用。重用 Session ID 需要服务器保存 Session 状态等,这样下次连接才能复用,这就需要服务器保存很多状态信息,所以耗费内存。

开启Session ID:
ssl_session_cache off | none | [builtin[:size]] [shared:name:size]
ssl_session_cache shared:SSL:50m; #储存SSL会话的缓存类型和大小,建议使用shared共享缓存类型
ssl_session_timeout 1d; #缓存的会话参数时间

Session ticket resumption

Session Ticket:服务端内存中不保存客户端会话信息,所有会话信息由客户端保存,类似于Cookie。TLS首次握手时,服务端用一个密钥将会话信息进行加密,通过New Session Ticket子协议发送给客户端,后续TLS握手时,客户端Client Hello携带Session Ticke,服务端用密钥对Session Ticket进行解密,若解密成功,则直接恢复会话。不再进行后续握手过程。

开启Session Ticket:
ssl_session_tickets on;
ssl_session_ticket_key current.key;
ssl_session_ticket_key previous.key;

如果没有配置key文件,则openssl默认生成随机key;只有在重启时才会重新生成。

如果用了多个key文件,则仅第一个key用来加密和解密;其它的用来解密。

在 Apache 中可以通过 SSLTicketKeyDefault 配置

Session ID resumption 与 Session ticket resumption

复用 session ticket 和 复用 session ID 的区别在于,复用 session ID 时在服务器和客户端存储了 key,连接时比对两边的数据是否一致;而 session ticket 将数据加密后存储在客户端,客户端请求时带回数据让服务器解密,正常则复用,只有发布的服务端能够解密该数据。

如果在握手阶段 session ID 和 session ticket 都提供了,将以 session ticket 为准,如果在 session ticket 阶段被 pass 掉了才通过 session id 取 cache 中的信息来复用。

HTTP Public-Key-Pins

任何一家受信任的 CA 都可以签发任意网站的站点证书,浏览器识别起来都是合法的,这些受信任的 CA 可以签发任意网站的站点证书(包括你的站点),而这些受信任的 CA 有很多,如果某 CA 中的某链被攻破,就可以造成由伪造或不正当手段获得网站证书的中间人攻击。

所以 Public-Key-Pins 就是用来告诉浏览器当前网站的证书指纹,包括配置过期时间,在过期时间内,浏览器再次访问这个网站的话就必须验证证书链中的证书指纹,如果跟之前指定的证书指纹不匹配,就无法访问。

生成pin-sha256指纹

注意:我们需要指定一个备用指纹,这个指纹并不是当前域名证书链中的指纹,应该是一个不在当前链中,未来有可能更换到该链的备用指纹。

通过 RSA key 文件生成:

openssl rsa -in my-rsa-key-file.key -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64

通过 ECC key 文件生成:

openssl ec -in my-ecc-key-file.key -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64

通过 CSR 文件生成:

openssl req -in my-signing-request.csr -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64

通过域名生成:

openssl s_client -servername www.example.com -connect www.example.com:443 | openssl x509 -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64

配置HPKP

Nginx配置如下:

add_header Public-Key-Pins 'pin-sha256="base64=="; max-age=expireTime [; includeSubDomains][; report-uri="reportURI"]';

Apache配置如下:

Header always set Public-Key-Pins "pin-sha256=\"base64+primary==\"; pin-sha256=\"base64+backup==\"; max-age=5184000; includeSubDomains"
  • pin-sha256:Base64加密的证书指纹;一般情况至少指定两个,其中包含一个备用指纹。
  • max-age:过期时间,秒
  • includeSubDomains:是否包含子域
  • report-uri:可选参数;验证失败时的上报地址

一些常见的问题可以参考:HTTP Public Key Pinning: You’re doing it wrong!

DNS CAA

CAA(Certificate Authority Authorization),即证书颁发机构授权。CAA标准要求CA机构在为域名签发证书时执行CAA强制性检查:

  • 如果检查域名的DNS解析记录,发现未设置CAA字段,则为该域名颁发证书。这种情况下,任何CA机构均可为该域名签发证书,存在HTTPS证书错误颁发的风险。
  • 如果检查域名的DNS解析记录,在CAA字段发现获得授权,则为该域名颁发证书。
  • 如果检查域名的DNS解析记录,在CAA字段发现未获得授权,则拒绝为该域名颁发证书,防止未授权HTTPS证书错误颁发。

约束和限制

CAA记录集的格式为:[flag] [tag] [value],由一个标志字节的[flag]和一个[tag]-[value](标签-值)对组成。

  • flag:认证机构限制标志,定义为0~255无符号整型。常用取值为0。
  • tag:仅支持大小写字母和数字0~9,长度1~15,常用取值:
    • issue:授权任何类型的域名证书
    • issuewild:授权通配符域名证书
    • iodef:指定违规申请证书通知策略
  • value:域名或用于违规通知的电子邮箱或Web地址。其值取决于[tag]的值,必须加双引号。取值范围:字符串(仅包含字母、数字、空格、-#*?&_~=:;.@+^/!%),最长255字符。

设置 CAA

参考如下:

0 issue "ca.abc.com"
0 issuewild "ca.def.com"
0 iodef "mailto:[email protected]"

该字段表示域名domain.com:
授权CA机构ca.abc.com颁发不限类型的证书。
授权CA机构ca.def.com颁发通配符证书。
禁止其他CA机构颁发证书。
当有违反设置规则的情况发生,CA机构发送通知邮件到[email protected]

也可以使用CAA Record Helper来自动生成。将生成的记录值填入到 DNS 解析中既可。

X-XSS-Protection 响应头

防止 XSS 攻击,在检查到XSS攻击时,停止渲染页面。现在主流浏览器都支持,并且默认开启。

add_header X-Xss-Protection "1; mode=block";

X-Frame-Options 响应头

用来给浏览器指示是否允许一个页面在 <frame><iframe> 或者 <object> 中展现的标记。通过设置 X-Frame-Options HTTP 响应头,可以确保自己的网站内容没有被嵌到别人的网站中去,也从而避免了点击劫持 (clickjacking) 的攻击。

有三个值:

  • DENY
    表示该页面不允许在 frame 中展示,即便是在相同域名的页面中嵌套也不允许。
  • SAMEORIGIN
    表示该页面可以在相同域名页面的 frame 中展示。
  • ALLOW-FROM uri
    表示该页面可以在指定来源的 frame 中展示。

CSP Level 2 规范中的 frame-ancestors 指令会替代这个非标准的 header。CSP 的 frame-ancestors 会在 Gecko 4.0 中支持,但是并不会被所有浏览器支持。然而 X-Frame-Options 是个已广泛支持的非官方标准,可以和 CSP 结合使用。

Apache 配置:在site的配置中

Header always append X-Frame-Options SAMEORIGIN

Nginx 配置:在httpserverlocation的配置中

add_header X-Frame-Options SAMEORIGIN;

参考资料:

Nginx配置HTTPS详解
更快更安全,HTTPS 优化总结
版权声明:此篇文章《服务器搭建记录 · 配置HTTPS》作者:湙凇。未经许可严禁转载,转载与引用请首先注明作者(湙凇)、出处(https://blog.yisrime.xyz/02/08/%e6%9c%8d%e5%8a%a1%e5%99%a8%e6%90%ad%e5%bb%ba%e8%ae%b0%e5%bd%95-%c2%b7-%e9%85%8d%e7%bd%aehttps.html)以及此段内容。
暂无评论

发送评论 编辑评论

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

版权所有 严禁复制