在 Qualys SSL Labs SSL 测试中获得 A+ 评级的秘技 2020版

本系列文章将阐述主流应用交付控制器和主流 Web 服务器如何运行 HTTP/2 和 TLSv1.3 协议,以及如何在 SSL Test 中获得 A+ 评级。

Posted by sysin on 2020-06-01
Estimated Reading Time 39 Minutes
Words 7.7k In Total
Viewed Times

作者:gc(at)sysin.org,主页:www.sysin.org

请访问 www.sysin.org 获得最新版,文章内容将持续补充更新。

Qualys SSL Labs 简介

Qualys,Inc.(NASDAQ:QLYS)是云安全和合规解决方案的先驱和领先提供商,在 100 多个国家拥有 6700 多个客户,其中包括福布斯全球 100 强和财富 100 强中的大多数。QualysGuard 云平台和集成解决方案套件通过按需提供关键的安全智能并自动化 IT 系统和 web 应用程序的全方位审核、法规遵从性和保护,帮助组织简化安全操作并降低合规成本。Qualys 成立于 1999 年,与英国电信、戴尔安全工程、富士通、IBM、NTT、Symantec、Verizon 和 Wipro 等领先的托管服务提供商和咨询机构建立了战略合作关系。该公司还是云安全联盟(CSA)的创始成员。

SSL Labs 推出的全球知名的 SSL 网站在线检测工具,会对 HTTPS 网站的证书链、安全性、性能、协议细节进行全面检测,检测完毕后会进行打分,同时给出一份详细的检测报告和改进建议。

测试网站:https://www.ssllabs.com/ssltest/

测试规则概述

2020年算法变更

January 2020

主要是修改了 TLS 1.0 和 TLS 1.1 的评分标准,TLS 1.0 和 TLS 1.1 是分别于 1996 年和 2006 年发布的老版协议,使用的是弱加密算法和系统。比如 SHA-1 和 MD5,这些算法和系统十分脆弱,存在重大安全漏洞,容易受到降级攻击的严重影响,而在 2008 年和 2017 年分别发布了协议的新版本,即 TLS 1.2TLS 1.3,无疑更优于旧版本,使用起来也更安全。

2018 年,在春季 TLS 1.3 版本发布之后,苹果、谷歌、Mozilla 和微软四大浏览器制造商于 2018 年 10 月联合宣布计划在 2020 年初取消对 TLS 1.0 和 TLS 1.1 的支持。

主流浏览器客户端都提供了禁用 TLS 1.0 和 TLS 1.1 协议的大致期限:

Browser Name Date
Microsoft IE and Edge First half of 2020
Mozilla Firefox March 2020
Safari/Webkit March 2020
Google Chrome January 2020

备注:由于受 COVID-19 影响,浏览器厂商推迟了 TLS 1.0 和 1.1 版本协议的淘汰时间。

Existing Grades Sample

Server Configuration Grade
TLS 1.2, TLS 1.1, TLS 1.0 + HSTS + No Warning + TLS_FALLBACK_SCSV A+
TLS 1.2, TLS 1.1, TLS 1.0 + HSTS + No Warning + No support for TLS_FALLBACK_SCSV A
TLS 1.2, TLS 1.1, TLS 1.0 + HSTS + Warnings + No support for TLS_FALLBACK_SCSV A-

Future Grades Sample

Server Configuration Grade
TLS 1.2, TLS 1.1, TLS 1.0 + HSTS + No Warning + TLS_FALLBACK_SCSV B
TLS 1.2, TLS 1.1, TLS 1.0 + HSTS + No Warning + No support for TLS_FALLBACK_SCSV B
TLS 1.2, TLS 1.1, TLS 1.0 + HSTS + Warnings + No support for TLS_FALLBACK_SCSV B
TLS 1.2 + HSTS + No Warning + TLS_FALLBACK_SCSV A+
TLS 1.2 + HSTS + No Warning + No support for TLS_FALLBACK_SCSV A
TLS 1.2 + HSTS + Warnings + No support for TLS_FALLBACK_SCSV A-

References

1. F5 BIG-IP

F5 BIG-IP 默认 B 级别(本例基于当前最新的 BIG-IP 16.0.0)

TLS 1.2 + HSTS + No Warning + TLS_FALLBACK_SCSV = A+

(No Warning 即受信任 SSL 证书,TLS_FALLBACK_SCSV F5 默认支持)

故:A 级别 + 开启 HSTS = A+,推荐启用 TLSv1_3 和 HTTP/2

其他应用交付产品可以参照 F5 配置

Ciphers 配置:A 级别 (TLSv1.2)

根据2020年1月算法变更,需要 TLSv1.2 及以上版本才能获得 A,新的 A 级别如下:

1
ECDHE+AES-GCM:ECDHE+AES-GCM:ECDHE+AES:ECDHE+3DES:RSA+AES-GCM:RSA+AES:RSA+3DES:-MD5:-RC4:-SSLv3:-TLSv1:-TLSv1_1

或者:

1
ECDHE+AES-GCM:ECDHE+AES:ECDHE+3DES:RSA+AES-GCM:RSA+AES:RSA+3DES:-MD5:-RC4:-SSLv3:-TLSv1:-TLSv1_1

F5 Cipher TLS 版本写法(与 nginx 和 apache 等使用 OpenSSL 的软件略有不同):

TLSv1
TLSv1_1
TLSv1_2
TLSv1_3

执行步骤:

编辑 SSL Profile,修改 Ciphers,将默认 Default 替换上述内容。

启用 HSTS

HSTS(HTTP Strict Transport Security,RFC6797),即 HTTP 严格安全传输,是国际互联网工程组织 IETF 正在推行一种新的 Web 安全协议,网站采用 HSTS 后,用户访问时无需手动在地址栏中输入 HTTPS,浏览器会自动采用 HTTPS 访问网站地址,从而保证用户始终访问到网站的加密链接,保护数据传输安全。HSTS 的作用是强制客户端(如浏览器)使用HTTPS与服务器创建连接。服务器开启 HSTS 的方法是,当客户端通过 HTTPS 发出请求时,在服务器返回的超文本传输协议响应头中包含 Strict-Transport-Security 字段。

Preload List:让防御更加彻底

HSTS 存在一个比较薄弱的环节,那就是浏览器没有当前网站的 HSTS 信息的时候,或者第一次访问网站的时候,依然需要一次明文的 HTTP 请求和重定向才能切换到 HTTPS,以及刷新 HSTS 信息。而就是这么一瞬间却给攻击者留下了可乘之机,使得他们可以把这一次的 HTTP 请求劫持下来,继续中间人攻击。针对这种攻击,HSTS 也有应对办法,那就是在浏览器里内置一个列表 Preload List,只要是在这个列表里的域名,无论何时、何种情况,浏览器都只使用 HTTPS 发起连接。这个列表由 Google Chromium 维护,FireFox、Safari、IE等主流浏览器均在使用。

可以通过官网(https://hstspreload.org),查询网站是否在 Preload List,可以申请将网站加入到 Preload List

执行步骤:

v12 及以上版本直接在 TMUI 中 Enabling HSTS in the HTTP profile 或者使用 iRuels

v11 及以下可以只能通过 iRules 实现

1
2
3
4
### iRule for HSTS HTTP Virtuals ###
when HTTP_REQUEST {
HTTP::respond 301 Location "https://[HTTP::host][HTTP::uri]"
}
1
2
3
4
5
6
7
### iRule for HSTS HTTPS Virtuals ###

## 31536000 sec = 1 Year

when HTTP_RESPONSE {
HTTP::header insert Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
}

OR

1
2
3
when HTTP_RESPONSE {
HTTP::header insert Strict-Transport-Security "max-age=31536000; includeSubDomains"
}

其中:

  • max-age 是必选参数,是一个以秒为单位的数值,它代表着 HSTS Header 的过期时间,通常设置为 1年,即 31536000秒。
  • includeSubDomains 是可选参数,如果包含它,则意味着当前域名及其子域名均开启 HSTS 保护。
  • preload 是可选参数,只有当你申请将自己的域名加入到浏览器内置列表的时候才需要使用到它。

启用 TLSv1_3

BIG-IP v14 开始支持 TLSv1_3(In BIG-IP 14.0.0, the BIG-IP system adds limited support for Transport Layer Security (TLS) 1.3. Starting in BIG-IP 14.1.0.1 and later, this support was updated to provide production level support for TLS 1.3.)

默认没有启用:By default, TLS 1.3 is disabled. To enable TLS 1.3, you must remove the No TLSv1.3 option from the Enabled Options list in the Configuration utility for the Client SSL and Server SSL profiles

You can view a list of TLS 1.3 supported ciphers and groups using the following TMOS Shell (tmsh) commands:

  • To view the supported client-side ciphers, use the following command:

    tmsh run util clientssl-ciphers TLSv1_3

  • To view the supported server-side ciphers, use the following command:

    tmsh run util serverssl-ciphers TLSv1_3

配置启用 TLSv1_3

编辑 ClientSSL Profle:

Ciphers:选择 Cipher Group,下拉选择 f5-secure

Options:Options List…

Enabled Options,
Disable No TLSv1.3
添加,No TLSv1 和 No TLSv1.1,保留默认的“Don’t insert empty fragments”

配置 HTTP/2

详见官方文档

配置 HTTP/2 就是在启用 HTTP profile 的 VS 上关联一个 HTTP/2 profile,核心参数配置任然在原有的 HTTP profile 上。

特殊配置是 SSL profile 要取消勾选 Renegotiation,其他都可以使用默认配置。

TLS-FALLBACK-SCSV

TLS-FALLBACK-SCSV(TLS Fallback Signaling Cipher Suite Value)是 OpenSSL 的一种阻止协议降级攻击的特性和机制。F5 BIG-IP,Nginx 和 Apache httpd 的 HTTPS 皆基于 OpenSSL 实现,符合要求的 OpenSSL 版本即可支持。

Poodle and TLS-FALLBACK-SCSV

SSLv3 allows exploiting of the POODLE bug. This is one more major reason to disable this.

Google have proposed an extension to SSL/TLS named TLS FALLBACK SCSV that seeks to prevent forced SSL downgrades. This is automatically enabled if you upgrade OpenSSL to the following versions:

  • OpenSSL 1.0.1 has TLS FALLBACK SCSV in 1.0.1j and higher.
  • OpenSSL 1.0.0 has TLS FALLBACK SCSV in 1.0.0o and higher.
  • OpenSSL 0.9.8 has TLS FALLBACK SCSV in 0.9.8zc and higher.

TLS Fallback Signaling Cipher Suite Value (SCSV) for Preventing Protocol Downgrade Attacks。

2. Microsoft IIS

根据规则:TLS 1.2 + HSTS + No Warning + TLS_FALLBACK_SCSV = A+

理论上 Windows & IIS 不支持 TLS_FALLBACK_SCSV,所以无法 A+,但是开启 HSTS,并仅启用 TLS1.2 可以获得 A+ 得分,这样就不存在协议降级风险。

Microsoft 的 SSL 基于 Schannel 实现,与 OpenSSL 无关(或称 Microsoft TLS)。

Schannel is a Security Support Provider (SSP) that implements the Secure Sockets Layer (SSL) and Transport Layer Security (TLS) Internet standard authentication protocols.
The Security Support Provider Interface (SSPI) is an API used by Windows systems to perform security-related functions including authentication. The SSPI functions as a common interface to several SSPs, including the Schannel SSP.

IIS 获得 A 级别

测试环境:IIS 10 on Windows Server 2019

执行 ps 脚本 或者使用 IIS Crypto,将获得A,这里以 IIS Crypto 为例:

IIS Crypto:点击 “Best Pratices”,Server Protocols 只勾选 TLS 1.2,Apply 并重启生效。

IISCrypto

仅启用 TLS 1.2 将获得 A,远程桌面也可以正常连接,启用 HSTS 将获得 A+。

在早期的 Windows 版本中,仅启用 TLS 1.2 远程桌面将无法连接。

HSTS

IIS 管理器 – 选择站点 – 高级设置 – HSTS

IIS--HSTS
IIS--HSTS

TLSv1.3

IIS 10 & Windows Server 2019 正式版尚未支持,参看这里

最新的 Windows Insider Preview 已经支持 TLS 1.3,并且通过 MSQUIC 实验性的支持 HTTP/3。

the latest Windows Insider Preview Builds for Schannel’s TLS 1.3 support.

HTTP/2

版本要求:

HTTP2 requires Windows 2016 with IIS 10 or later.

配置方法:

首先配置好 SSL 证书并创建 HTTPS 站点,IIS 10 默认开启 HTTP/2 协议,所以我们都不用额外去设置(可以禁用,新建站点时或者”编辑网站” > “绑定…”勾选”禁用 HTTP/2”)。

IIS--HTTP/2

3. Nginx

Nginx SSL 证书配置方法

官方文档

1
2
3
4
5
6
7
8
9
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate www.example.com.crt;
ssl_certificate_key www.example.com.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
...
}

证书文件使用 PEM 格式。

证书文件使用相对路径时,证书文件要放在主配置文件相同目录下(默认 /etc/nginx)。

更多配置,这篇文章可以参考:Strong SSL Security on nginx

TLSv1.3

版本支持如下:

  • The TLSv1.1 and TLSv1.2 parameters (1.1.13, 1.0.12) work only when OpenSSL 1.0.1 or higher is used.
  • The TLSv1.3 parameter (1.13.0) works only when OpenSSL 1.1.1 built with TLSv1.3 support is used.

More info on the NGINX documentation

HTTP/2

版本要求

openssl 的版本必须在 1.0.2e 及以上,执行以下命令验证:

1
openssl version

nginx 的版本必须在 1.9.5 以上,需要添加 –with-http_v2_module 模块,执行以下命令验证:

1
nginx -V

参考配置

以下配置:启用 HTTP/2、TLSv1.3、推荐的 Ciphers、HSTS,可以获得 A+ 得分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
server {
#listen 443 ssl;
listen 443 ssl http2; # HTTP/2 Enable
listen [::]:443 ssl http2; # IPv6
server_name www.sysin.org;
ssl_certificate www.sysin.org.crt;
ssl_certificate_key www.sysin.org.key;
ssl_protocols TLSv1.2 TLSv1.3; # Requires nginx >= 1.13.0 else use TLSv1.2
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!kRSA;
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload" always;
...
}

#ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
#ssl_ciphers HIGH:!aNULL:!MD5; #B
#ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!kRSA; #A
#ssl_ciphers ALL:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!RC4; #B
#ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384; #A (Mozilla Intermediate)

4. Kubernetes ingress-nginx

概述

默认 TLS 版本和 Ciphers

nginx-ingress 默认仅使用 TLS 1.2 和 1.3, with a secure set of TLS ciphers.

默认 cipher 列表: 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.

Legacy TLS 支持

如果需要兼容一些老旧的浏览器和操作系统,需要使用 ConfigMap 修改默认配置,例如:

mozilla-ssl-config-old

1
2
3
4
5
6
7
kind: ConfigMap
apiVersion: v1
metadata:
name: nginx-config
data:
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:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA"
ssl-protocols: "TLSv1 TLSv1.1 TLSv1.2 TLSv1.3"

HSTS 默认启用

可以在 ConfigMap 中配置参数 hsts: "false" 禁用默认行为

HTTP redirect

对于 TLS 类型的 ingress,控制器默认将 HTTP 请求定向到 HTTPS(308 Permanent Redirect response),

可以在 NGINX config map, 中使用 ssl-redirect: "false" 参数全局禁用,或者针对单个 ingress 规则使用 annotation nginx.ingress.kubernetes.io/ssl-redirect: "false" 来禁用。

本例部署的 ingress-nginx 版本为 0.30.0,经过测试只要使用受信任证书,即可获得 A+ 得分。

示例

以下发布 Dashboard 为例,配置受信任 SSL 证书

查看 Dashboard 已经正常部署(部署 Dashboard 参看其他文档):

1
kubectl get po,svc -n kubernetes-dashboard -o wide

部署受信任的 SSL 证书:

1
2
3
4
5
6
7
# 创建 secret,在 ingress 不能直接使用证书需要转换为 secret 才能使用
# key 和 cert 都为 PEM 格式,cert 包含证书文件和证书链部分
kubectl create secret tls dashboard-ingress-tls --key dashboard-ingress.key --cert dashboard-ingress.crt -n kubernetes-dashboard
# 查看 secret 内容
kubectl get secret dashboard-ingress-tls -n kubernetes-dashboard -o yaml
# 删除命令
kubectl delete secret dashboard-ingress-tls -n kubernetes-dashboard

配置 ingress 转发文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# vi dashboard-ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
name: kubernetes-dashboard-ingress
namespace: kubernetes-dashboard #注意修改
spec:
tls:
- secretName: dashboard-ingress-tls #上述创建的secret
rules:
- host: k8s.sysin.cn #域名
http:
paths:
- path: /
backend:
serviceName: kubernetes-dashboard
servicePort: 443

host: 对应的域名
path: url上下文
backend: 后向转发到对应的 serviceName: 和 servicePort:

注意,dashboard 默认使用 https 提供服务,ingress 默认 backend-protocol 使用 http,这里发布成功的关键是要添加 annotations 参数

1
2
3
annotations:
nginx.ingress.kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"

部署:

1
kubectl apply -f dashboard-ingress.yaml

部署成功后可以通过域名访问:https://k8s.sysin.cn

5. Apache httpd

基本配置

参看官网文档

1
2
3
4
5
6
7
8
9
10
11
LoadModule ssl_module modules/mod_ssl.so

Listen 443
<VirtualHost *:443>
ServerName www.example.com
SSLEngine on
SSLCertificateFile "/path/to/www.example.com.cert"
SSLCertificateKeyFile "/path/to/www.example.com.key"
SSLCipherSuite HIGH:!aNULL:!MD5
#SSLCipherSuite RC4-SHA:AES128-SHA:HIGH:!aNULL:!MD5
</VirtualHost>

HTTP/2

Apache Module mod_http2 Available in version 2.4.17 and later

两种配置:

HTTP/2 in a VirtualHost context (TLS only)

1
Protocols h2 http/1.1

Allows HTTP/2 negotiation (h2) via TLS ALPN in a secure <VirtualHost>. HTTP/2 preamble checking (Direct mode, see H2Direct) is disabled by default for h2.

HTTP/2 in a Server context (TLS and cleartext)

1
Protocols h2 h2c http/1.1

Allows HTTP/2 negotiation (h2) via TLS ALPN for secure <VirtualHost>. Allows HTTP/2 cleartext negotiation (h2c) upgrading from an initial HTTP/1.1 connection or via HTTP/2 preamble checking (Direct mode, see H2Direct).

HSTS

1
2
3
4
# Load modules (or use the IfModule)
LoadModule headers_module modules/mod_headers.so

LoadModule rewrite_module modules/mod_rewrite.so

Rewrite HTTP connections and redirect them to HTTPS:

1
2
3
4
5
6
7
# Redirect HTTP connections to HTTPS

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>

Now configure the virtual host:

1
2
3
<VirtualHost *:443>
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
</VirtualHost>

TLSv1.3

版本要求:

Apache version 2.4.36 or greater. (网上文章传言 2.4.38 是错误的!)

OpenSSL version 1.1.1 or greater.

CentOS 8 和 Ubuntu 20.04 自带软件包满足要求,低版本需要编译安装。

1
2
3
4
5
6
[[email protected]c8 ~]# openssl version
OpenSSL 1.1.1c FIPS 28 May 2019

[[email protected]c8 ~]# dnf list httpd
Installed Packages
httpd.x86_64 2.4.37-21.module_el8.2.0+382+15b0afa8 @AppStream
1
2
3
4
5
6
[email protected]u20:~# openssl version
OpenSSL 1.1.1f 31 Mar 2020

[email protected]u20:~# apt list apache2
Listing... Done
apache2/focal 2.4.41-4ubuntu3 amd64

仅启用 TLS 1.2

1
SSLProtocol -all +TLSv1.2

配置项如下所示:

1
2
3
4
5
6
7
8
9
<VirtualHost *:443>
ServerName www.example.com
DocumentRoot /var/www/html

SSLEngine on
SSLProtocol -all +TLSv1.2
SSLCertificateFile "/path/to/www.example.com.cert"
SSLCertificateKeyFile "/path/to/www.example.com.key"
</VirtualHost>

启用 TLS 1.3 和 1.2

The Apache version 2.4.36 or higher versions support TLS v1.3. You must upgrade Apache packages before enabled TLS 1.3 in SSL settings.

1
SSLProtocol -all +TLSv1.2 +TLSv1.3

配置项如下所示:

1
2
3
4
5
6
7
8
9
<VirtualHost *:443>
ServerName www.example.com
DocumentRoot /var/www/html

SSLEngine on
SSLProtocol -all +TLSv1.2 +TLSv1.3
SSLCertificateFile "/path/to/www.example.com.cert"
SSLCertificateKeyFile "/path/to/www.example.com.key"
</VirtualHost>

记得重启 Apache 服务才能生效。

参考配置

1
2
3
# For CentOS
yum install mod_ssl
mv /etc/httpd/conf.d/ssl.conf /etc/httpd/conf.d/ssl.conf.bak

配置文件自动增加”/etc/httpd/conf.modules.d/00-ssl.conf”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
echo '
Listen 443
<VirtualHost *:443>
Protocols h2 http/1.1
ServerName sysin.org
DocumentRoot /var/www/html
SSLEngine on
SSLProtocol -all +TLSv1.2 +TLSv1.3
SSLCertificateFile "/etc/httpd/ssl/sysin.org.pem"
SSLCertificateKeyFile "/etc/httpd/ssl/sysin.org.key"
SSLCipherSuite HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!kRSA
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
</VirtualHost>
' > /etc/httpd/conf.d/sysin.org.conf

其他 Cipher 参考配置

1
2
SSLCipherSuite HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!kRSA  #A
SSLCipherSuite ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384 #A (Mozilla Intermediate)

6. Apache Tomcat

Tomcat 不使用 OpenSSL,所以不支持 TLS-FALLBACK-SCSV 特性,在 Tomcat 9 最新版默认配置即可获得 A 得分,开启 HSTS 也是 A 得分。

基本配置

打开 conf/server.xml 文件可以看到默认的 SSL/TLS HTTP/1.1 和 HTTP/2 配置方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!-- Define an SSL/TLS HTTP/1.1 Connector on port 8443
-->
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true">
<SSLHostConfig>
<Certificate certificateKeystoreFile="conf/localhost-rsa.jks"
type="RSA" />
</SSLHostConfig>
</Connector>

<!-- Define an SSL/TLS HTTP/1.1 Connector on port 8443 with HTTP/2
-->
<Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol"
maxThreads="150" SSLEnabled="true" >
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
<SSLHostConfig>
<Certificate certificateKeyFile="conf/localhost-rsa-key.pem"
certificateFile="conf/localhost-rsa-cert.pem"
certificateChainFile="conf/localhost-rsa-chain.pem"
type="RSA" />
</SSLHostConfig>
</Connector>

Certificate 参数配置参考

HTTP/2

版本要求:Tomcat 8.5.0,2016-03-24,开始支持 HTTP/2

配置 HTTP/2:即增加 <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />

根据官方文档使用 PEM 格式证书测试失败,这里使用 PFX 格式。

Tomcat 9 强制要求证书别名设置为 tomcat。您需要使用以下 keytool 命令(这里的证书原来别名是 alias,阿里云申请的免费证书默认别名)转换证书别名为 tomcat:

keytool -changealias -keystore my-cert.pfx -alias alias -destalias tomcat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- Define an SSL/TLS HTTP/1.1 Connector on port 443 with HTTP/2
-->
<Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true">
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
<SSLHostConfig protocols="TLSv1.2+TLSv1.3"
ciphers="HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!kRSA" >
<Certificate certificateKeystoreFile="conf/k8s.sysin.cn.pfx"
certificateKeystoreType="PKCS12"
certificateKeystorePassword="your-pfx-password" />
</SSLHostConfig>
</Connector>

<!-- 默认参数如下:
hostName= default:`_default_`
ciphers= default:`HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!kRSA`
protocols= default:`all`
-->

ciphers 参看:CiphersHowTo SSLCiphers

protocols 写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
The names of the protocols to support when communicating with clients. This should be a list of any combination of the following:

SSLv2Hello
SSLv3
TLSv1
TLSv1.1
TLSv1.2
TLSv1.3
all

Each token in the list can be prefixed with a plus sign ("+") or a minus sign ("-"). A plus sign adds the protocol, a minus sign removes it form the current list. The list is built starting from an empty list.

The token all is an alias for SSLv2Hello,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3.

Note that TLSv1.3 is only supported for JSSE when using a JVM that implements TLSv1.3.

Note that SSLv2Hello will be ignored for OpenSSL based secure connectors. If more than one protocol is specified for an OpenSSL based secure connector it will always support SSLv2Hello. If a single protocol is specified it will not support SSLv2Hello.

Note that SSLv2 and SSLv3 are inherently unsafe.

If not specified, the default value of all will be used.

HSTS

Response Header 配置

Enabling HSTS (to include maxAgeSeconds = 31536000, includeSubDomains, and preload) requires two modifications of the Tomcat’s conf/web.xml file:

1). 启用 HSTS 支持,查找以下部分(通过搜索 “httpHeaderSecurity” 关键词):

1
2
3
4
5
6
7
<!--
<filter>
<filter-name>httpHeaderSecurity</filter-name>
<filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-class>
<async-supported>true</async-supported>
</filter>
-->

替换为(或者新增):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<filter>
<filter-name>httpHeaderSecurity</filter-name>
<filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-class>
<init-param>
<param-name>hstsEnabled</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>hstsMaxAgeSeconds</param-name>
<param-value>31536000</param-value>
</init-param>
<init-param>
<param-name>hstsIncludeSubDomains</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>hstsPreload</param-name>
<param-value>true</param-value>
</init-param>
<async-supported>true</async-supported>
</filter>

2). 继续搜索 “httpHeaderSecurity” 关键词,查找如下内容,在 “Built In Filter Mappings” 这一段:

1
2
3
4
5
6
7
<!--
<filter-mapping>
<filter-name>httpHeaderSecurity</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
-->

移除注释,如下:

1
2
3
4
5
<filter-mapping>
<filter-name>httpHeaderSecurity</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>

HTTP redirection

编辑 server.xml,将 HTTP 重定向到 HTTPS,这里分别使用 80 和 443 端口,搜索 “Connector” 关键词,查找到如下部分:

1
2
3
4
5
6
<!--
<Connector executor="tomcatThreadPool"
port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
-->

修改为:

1
2
3
4
<Connector executor="tomcatThreadPool"
port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="443" />

或者修改这里:

1
2
3
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />

修改为:

1
2
3
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="443" />

7. HAProxy

SSL cipher

Global 参数中关于 SSL 的配置

以下三个参数是定义 frontend

1
ssl-default-bind-ciphers <ciphers> #适用于 TLSv1.2及以下版本
1
ssl-default-bind-ciphersuites <ciphersuites> #OpenSSL 1.1.1 or later,TLSv1.3

同时需要同时支持 TLSv1.2 及以下版本和 TLSv1.3 两个参数需要同时设置。

示例:

1
ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
1
ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets

以下对应定义 backend server

适用于 TLSv1.2及以下版本

适用于 OpenSSL 1.1.1 or later,TLSv1.3

参看官方文档:Configuring TLS Settings

参考配置:

1
2
3
4
5
6
7
8
global
......
#ssl-default-bind-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 #for TLSv1.2, Mozilla Intermediate
ssl-default-bind-ciphers HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!kRSA #for TLSv1.2
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 #for TLSv1.3
ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
#ssl-default-bind-options prefer-client-ciphers no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets
.....

HTTP/2

HAProxy 1.8 及以上版本支持 HTTP/2

From the 1.8 announcement:

HAProxy 1.8 now supports HTTP/2 on the client side (in the frontend sections) and can act as a gateway between HTTP/2 clients and your HTTP/1.1 and HTTP/1.0 applications.

HTTP/2 协议已经被迅速采用,HAProxy 1.8 现在在客户端支持 HTTP/2(在前端部分),并且可以充当 HTTP/2 客户端与 HTTP/1.1 和 HTTP/1.0 应用程序之间的网关。

要启用对 HTTP/2 的支持,前端部分的绑定行必须配置为 SSL 端点,alpn 必须宣布 h2,如下:

1
2
3
frontend myapp
bind :443 ssl crt /path/to/cert.crt alpn h2,http/1.1
mode http

备注:cert.crt 证书采用 PEM 格式,包含私钥、证书,证书链在一个文件中。

TLSv1.3

要求:HAProxy 1.8.1 及以上,OpenSSL 1.1.1 及以上。

参数:ssl-default-bind-ciphersuites,参看上述 SSL cipher 部分的描述。

HSTS

方法如下:

1
2
3
4
5
6
7
frontend public

......

http-response add-header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"

......

Rewriting HTTP responses 方法示例

  • add-header

语法:

http-response add-header <name> <fmt> [<condition>]

示例:

http-response add-header X-Via %[env(HOSTNAME)]

  • set-header

相当于覆盖或者替换原有 header

语法:

http-response set-header <name> <fmt> [<condition>]

示例:

http-response set-header Server webserver #hide server header

  • del-header

语法:

http-response del-header <name> [<condition>]

示例:

http-response del-header X-Varnish

  • replace-value

高级替换

语法:

http-response replace-value <name> <match-regex> <replace-fmt> [<condition>]

Redirecting HTTP Requests

重定向 HTTP 请求到 HTTPS,可以参考以下官方示例:

Examples of traffic redirection

Append a www. prefix in front of all URLs that do not have it:

1
2
acl has_www hdr_beg(host) -i www
http-request redirect code 301 location http://www.%[hdr(host)]%[req.uri] unless has_www

Redirect all HTTP traffic to HTTPS when SSL is handled by haproxy:

1
2
acl http      ssl_fc,not
http-request redirect scheme https if http

Send redirects for requests for articles without a ‘/‘:

1
2
acl missing_slash path_reg ^/article/[^/]*$
http-request redirect code 301 prefix / drop-query append-slash if missing_slash

Move the login URL only to HTTPS:

1
2
3
4
5
6
7
8
9
10
11
acl http       ssl_fc,not
acl https ssl_fc
acl u_login path_beg /login
acl u_logout path_beg /logout
acl up_userid urlp_len(userid) gt 0
acl cookie_set hdr_sub(cookie) SEEN=1
http-request redirect scheme https if http u_login
http-request redirect prefix https://%[req.hdr(Host)] set-cookie SEEN=1 if !cookie_set
http-request redirect prefix https://%[req.hdr(Host)] drop-query if u_login !up_userid
http-request redirect scheme http if https !u_login
http-request redirect location / clear-cookie USERID= if u_logout

参考配置

Config files and scripts for HAProxy 1.8 with HTTP/2 and dynamic reconfiguration

An ‘haproxy.cfg’ with:

  • The ability to switch backends dynamically
  • HTTP/2 support in all browsers
  • Logging to systemd
  • The various www vs non-www, HTTP vs HTTPS combinations redirected to a single HTTPS site.
  • A branded ‘sorry’ page
  • A separate server that handles blogs and marketing content
  • Support for HTML5 Server Sent Events
  • An A+ on the SSL Labs test

See the full docs at fast EV HTTPS verification provider CertSimple.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
##https://github.com/certsimple/haproxy-http2-load-balancing-config/blob/master/haproxy.cfg
global
# Log to systemd's /dev/log compatibility socket
log /dev/log local0 info

chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon

# turn on stats unix socket - see http://cbonte.github.io/haproxy-dconv/1.8/configuration.html#3.1-stats%20socket
stats socket /var/lib/haproxy/stats mode 600 level admin
stats timeout 2m

# generated 2020-09-12, Mozilla Guideline v5.6, HAProxy 2.1, OpenSSL 1.1.1d, intermediate configuration
# https://ssl-config.mozilla.org/#server=haproxy&version=2.1&config=intermediate&openssl=1.1.1d&guideline=5.6
# intermediate configuration
ssl-default-bind-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-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
ssl-default-bind-options prefer-client-ciphers no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets
#ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets

ssl-default-server-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-default-server-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets

# curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam
ssl-dh-param-file /path/to/dhparam

defaults
mode http

# Needed for GeoIP
# Enable insertion of the X-Forwarded-For header to requests sent to servers
# May be used in sections :defaults frontend listen backend
# http://cbonte.github.io/haproxy-dconv/2.2/configuration.html#4.2-option%20forwardfor
option forwardfor

# See http://cbonte.github.io/haproxy-dconv/1.8/configuration.html#option%20http-server-close
option http-server-close

log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout client 1m
timeout server 1m

timeout check 10s
maxconn 3000

# From http://stackoverflow.com/questions/21419859/configuring-haproxy-to-work-with-server-sent-events
# Set the max time to wait for a connection attempt to a server to succeed
timeout connect 30s
# handle a client suddenly disappearing from the net
timeout client-fin 30s
option http-server-close

# The 'stats' site, where we see what's up and what's down - uncomment and set a password if you want it!
# stats enable
# stats uri /haproxy?stats
# stats realm Strictly\ Private
# stats auth someusername:i-am-an-awful-password-and-you-should-change-me

# Show a custom page during site maintenance (ie, when 'blue' and 'green' are both down)
errorfile 503 /etc/haproxy/errors/503-mycustom.http

frontend public
# HTTP/2 - see https://www.haproxy.com/blog/whats-new-haproxy-1-8/
# h2 is HTTP2 with TLS - see https://http2.github.io/faq/
# Order matters, so h2 before http1.1
bind :443 ssl crt /etc/https/cert-and-private-key-and-intermediate-and-dhparam.pem alpn h2,http/1.1

# Redirect http -> https
bind :80
redirect scheme https code 301 if ! { ssl_fc }

# Redirect www -> example.com
redirect prefix https://example.com code 301 if { hdr(host) -i www.example.com }

# HSTS (15768000 seconds = 6 months)
# HSTS (31536000 seconds = 1 years)
http-response set-header Strict-Transport-Security max-age=31536000

# Use the marketing site for marketing URLs
acl marketing path_beg -i /help /sitemap.xml /BingSiteAuth.xml /about /blog /videos/blog /images/blog /fonts/blog /css/blog /js/blog
use_backend marketing if marketing

# Everything else goes to the app servers
default_backend app
option httpclose
option forwardfor

backend marketing
balance roundrobin
server static 127.0.0.1:8000 check

backend app
# From http://blog.haproxy.com/2014/01/17/emulating-activepassing-application-clustering-with-haproxy/
# See also https://cbonte.github.io/haproxy-dconv/configuration-1.5.html#stick-table
stick-table type ip size 1m
stick on dst
# See https://cloud.digitalocean.com/droplets for these IPs
server green 10.1.1.1:8000 check
server blue 10.1.1.2:8000 check backup
# http://stackoverflow.com/questions/21419859/configuring-haproxy-to-work-with-server-sent-events
timeout tunnel 10h

8. Varnish with Hitch

Varnish Cache 是一种 web 应用程序加速器,同时以被用于缓存的 HTTP 反向代理而闻名。Varnish HTTP/2 前端通过 Hitch 代理实现。Hitch 是 Varnish Software 开发的基于 libev 的高性能 SSL/TLS 开源代理软件。

笔者写了一篇文章描述了整个配置过程,访问这里查看:Varnish with Hitch HTTP/2 implement on CentOS 8.0

启动 Varnish 支持 HTTP/2

默认情况下,Varnish 中的 HTTP/2 支持是禁用的,因此必须添加一个特性标志才能启用它。即通过传递“-p feature=+http2”作为 Varnish 的启动参数来实现。

您可以通过运行varnishadm param.show feature命令来检查是否已启用参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# varnishadm param.show feature

feature
Value is: none (default)

Enable/Disable various minor features.
none Disable all features.

Use +/- prefix to enable/disable individual feature:
short_panic Short panic message.
wait_silo Wait for persistent silo.
no_coredump No coredumps.
esi_ignore_https Treat HTTPS as HTTP in
ESI:includes
esi_disable_xml_check Don't check of body looks like
XML
esi_ignore_other_elements Ignore non-esi XML-elements
esi_remove_bom Remove UTF-8 BOM
https_scheme Also split https URIs
http2 Support HTTP/2 protocol
http_date_postel Relax parsing of timestamps in
HTTP headers

启动 Varnish

本例中,Varnish 使用默认配置,事先运行了 Nginx,将 Nginx 默认端口修改为 8080 即可(具体过程略)。

1
2
3
varnishd -a :80 -a localhost:6086,PROXY -p feature=+http2 -f /etc/varnish/default.vcl
#或者
varnishd -a localhost:6086,PROXY -p feature=+http2 -f /etc/varnish/default.vcl

验证 Varnish 已经开启 HTTP/2 支持

1
2
3
4
5
6
varnishadm param.show feature
feature
Value is: +http2
Default is: none

......

hitch 参考配置:Ciphers,HTTP/2 和 TLSv1.3

版本要求:

  • Cache 5.0 开始实验性的支持 HTTP/2
  • Varnish 6.0 完整支持 HTTP/2
  • hitch 1.5 版本开始支持 TLS 1.3

示例配置(更多参数参看官方文档):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
mv /etc/hitch/hitch.conf /etc/hitch/hitch.conf.bak

echo '
# Run 'man hitch.conf' for a description of all options.

frontend = {
host = "*"
port = "443"
}
backend = "[127.0.0.1]:6086" # 6086 is the default Varnish PROXY port.
workers = 4 # number of CPU cores

daemon = on

# We strongly recommend you create a separate non-privileged hitch
# user and group
user = "hitch"
group = "hitch"

# Enable to let clients negotiate HTTP/2 with ALPN. (default off)
# Varnish 启动参数必须增加 `-p feature=+http2`,开启 HTTP/2 特性(默认关闭)
alpn-protos = "h2, http/1.1"

# run Varnish as backend over PROXY; varnishd -a :80 -a localhost:6086,PROXY ..
write-proxy-v2 = on # Write PROXY header

syslog = on
log-level = 1

# Add pem files to this directory
#pem-dir = "/etc/pki/tls/private"

## PEM 文件包含 key、cert 和 chain 的组合,可以支持多个 PEM 文件
## cat example.com.key example.com.crt my-ca-bundle.crt > example.com.pem
pem-file = "/etc/hitch/varnish.pem"
# 定义第二个 PEM 文件
#pem-file = "/etc/hitch/mydomain.pem"
## 官方推荐默认 cipher
ciphers = "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"
## Hitch supports TLS (1.0, 1.1, 1.2, 1.3) and SSL 3. By default
tls-protos = TLSv1.2 TLSv1.3
## TCP Fast Open saves up to one full round-trip time (RTT) over the standard three-way connection handshake during a TCP session.
tcp-fastopen = on
' > /etc/hitch/hitch.conf

OCSP staple 相关配置参看官方文档

以上配置将获得 A 评级,加上下面的 HSTS 即可获得 A+ 评级。

HSTS

编辑 varnish vcl,如下字段添加:

1
2
3
sub vcl_deliver {
set resp.http.Strict-Transport-Security = "max-age=31536000; includeSubDomains; preload";
}



如果文章中使用的内容和图片侵犯了您的版权,请联系作者删除。如果您喜欢这篇文章或者觉得它对您有用,欢迎您发表评论,也欢迎您分享这个网站,或者赞赏一下作者,谢谢!


支付宝打赏 微信打赏

赞赏一下