HTTPS配置全记录(不定期更新版)

更新说明

2021-10-17: 合并旧文《Let’s HTTPS》中的部分并更新,增加自签名CA部分。 2021-11-16:增加查看证书。

缘起

前几天帮肾上TR@SOE(CSDN唯一一个用户名里有特殊字符的用户)部署一个HTTPS,虽然去年写过用Let’s Encrypt证书部署HTTPS的文章,但是这次略有不同,所以作个记录吧,顺便也把常见的做法都说一说。

环境

常见的部署环境和条件有以下几种情况组合:

  • Apache+自签名证书
  • Apache+免费或商业证书
  • Nginx+自签名证书
  • Nginx+免费或商业证书

免费证书和商业证书本质上是一样的,都是可以被系统承认的证书,只是申请方式不同而已。

证书

证书结构

配置一个HTTPS服务所需要的证书包括几个部分:

  • Server Key(服务器私钥)
  • CSR(Certificate Signing Request)
  • CRT(X509 Certificate)

创建证书的基本流程是这样:

  • 生成自己的服务端私钥
  • 输入基本信息并用私钥签名生成CSR
  • 提交CSR给证书机构CA(免费或商业证书)签名生成CRT,或自己做CA签名生成CRT(自签名证书)

其中前两个步骤都是一样的,在这里统一说明一下。

生成服务器私钥

openssl genrsa -out server.key 4096

输出的server.key文件就是服务器私钥,4096是密钥长度,要求不高的话用2048也可。

生成服务器CSR

openssl req -new -sha256 -key server.key -out server.csr

因为sha1已经不安全,所以这里用了sha256,可能太旧的客户端(比如win98?)会不支持。

server.csr就是生成的CSR,server建议用你的网站名标识会比较方便识别。

然后按提示输入:

  • 国家
  • 公司
  • 部门
  • 通用名(即网站域名,这个必须准确,有些商业证书支持在这里用带www的域名后签发出同时支持不带www的域名)
  • email
  • 密码(可选,设置的话以后重启webserver都需要输入密码)

自签名证书做法

简单自签名证书

生成服务器证书

openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt

其中签名用的KEY就是自己的服务端私钥,所以这是一个自签名证书。

有效期为3650天(即十年)。

自签名CA

以下是例子,除了key用椭圆曲线算法没用RSA以外,和域名证书的生成方式是一样的。

生成CA私钥:

openssl ecparam -out ca.key -name prime256v1 -genkey

使用的曲线为prime256v1,支持的曲线可以这样查看:

openssl ecparam -list_curves

生成CA的CSR(注意:CA必须使用单独的通用名称,不可以用此CA给此通用名称签发证书):

openssl req -new -sha256 -key ca.key -out ca.csr

生成CA的证书:

openssl x509 -req -sha256 -days 3650 -in ca.csr -signkey ca.key -out ca.crt

有了CA证书以后就可以来生成服务器证书了。

生成服务器私钥(这里也用椭圆曲线算法):

openssl ecparam -out server.key -name prime256v1 -genkey

生成服务器CSR:

openssl req -new -sha256 -key server.key -out server.csr

最关键的一步——用CA证书签发服务器证书:

openssl x509 -req -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -sha256

客户端使用自签名CA

因为自签名CA不在系统自带的CA列表里,所以由自签名CA签发的服务器证书不被客户端承认,访问时会报证书错误,这时需要把自签名的证书导入到客户端系统里。

这里以Linux为例:

mkdir -p /usr/share/ca-certificates/mycerts
cp /path_to_ca/ca.crt /usr/share/ca-certificates/mycerts/
dpkg-reconfigure ca-certificates
# 选择yes即可导入

之后就可以接受所有用此CA签发的服务器证书了。

免费证书生成

旧文《Let’as HTTPS》中关于Let’s Encrypt的部分已过时,新的方法要简单很多:

首先需要安装Let’s Encrypt官方客户端,顺便再装上nginx插件(最好用python3-pip安装,毕竟python2明年就不再支持了):

python3-pip install certbot certbot-nginx

然后就可以创建证书了,不再需要手工创建KEY和CSR,一步直接生成——甚至那个HTTP的nginx配置也会直接创建:

certbot run --nginx --email [your_email] -w /[path_to]/challenge -d [your_domain] --preferred-challenges http --renew-by-default --agree-tos

执行完就可以自动创建证书并保存,同时还会修改相应的nginx配置文件,非常方便。

如果想多个域名用同一个证书的话,可以加多个 -d 参数。

新的官方客户端还支持泛域名证书,不过就需要手工创建了,方法见《Let’s Encrypt的泛域名证书》。

更新证书也很简单:

certbot renew

即可自动更新本机所有的证书(当然不包括需要手工创建的泛域名证书)。

用以下命令则可以查看当前的所有证书:

certbot certificates

不想再要的证书也可以删除:

certbot delete

然后根据提示选择要删除的证书即可。

商业证书生成

首先找一个商业证书机构(CA)或其代理商下一个证书订单。

其次是选择证书类型。

证书类型

商业证书有很多类型,也有很多的CA可以选择,不同的CA,不同的类型价格也不一样。

常见的CA有:

  • VeriSign(Symantec)
  • GeoTrust(RapidSSL)
  • Comodo
  • ……

以上以价格从高到低排序。除此之外当然还有很多,具体可以打开你的系统证书列表看看。

需要特别说一句的就是:臭名昭著的CNNIC和沃通(WoSign,包括免费的StartSSL),已经被证明不安全,建议将它们从系统中删除,并且不要去申请使用它们的证书。

常见的证书类型有三种:

  • DV(域名验证)
  • OV(组织验证)
  • EV(扩展验证)

验证级别从低到高排序,价格也是如此。

DV证书只验证域名,在最终访问者那边查看证书时将不会包含CSR中的组织信息,只有域名信息,也就是说你就算是在CSR里输入你是GOOGLE,到了客户端那里也是看不到的。

OV证书除了验证域名还需要验证组织,即你需要提供证据证明你在CSR里输入的公司或组织的确是你, 这样才能在客户端证书里查看到你的组织信息。

EV证书就要求更高了,通常是金融机构之类的用。

除此之外,证书还有一种区别:

  • 单域名证书
  • 多域名证书
  • 泛域名证书

一样是价格从高到低排序。

单域名证书就是只能用于一个域名的证书,某些商业证书可以提供两个域名:带WWW的和不带WWW的。

多域名证书就是一个证书可以用于多个域名,默认支持三个域名,当然增加域名需要加钱,但比单独买单域名证书要便宜。适用于一个公司有多个域名,而且多个域名部署在一个服务器上,使用一个证书会比较省事,也比较便宜。

泛域名证书就是一个证书可以用于一个域名下的任意多个子域名。

申请流程

一般申请流程(仅指DV类型)如下:

  • 选择CA或代理商
  • 选择证书类型
  • 选择有效期(以年为单位,一般时间越长单价越便宜)
  • 下单付款
  • 成交后按服务商的邮件或文档开始验证域名(以下为一种流程,不同服务商可能不太一样)
    • 上传CSR(或用服务商提供的工具生成,但不推荐)
    • 选择验证方式(EMAIL,文件,DNS等)
    • 按相应方式操作
    • 等待验证
    • 取得证书(邮件或从服务商处自行下载):

其中各验证方式大致如下:

  • Email:证书机构向域名注册邮箱或域名的webmaster等邮箱(可选)发送验证邮件
  • 文件:在域名的指定路径下放验证文件供证书机构访问
  • DNS:创建指定的DNS TXT记录供证书机构验证

通过验证后即可获得证书。

证书内容一般包括:域名的CRT,证书机构的CRT链(可能有多个),根证书CRT(CA的证书),如果用服务商的工具生成CSR,还应该会有CSR和KEY。

查看,转换和测试

查看key,CSR和X509证书

# key
openssl rsa -noout -text -in server.key
# csr
openssl req -noout -text -in server.csr
# x509证书
openssl x509 -noout -text -in server.crt

证书格式转换

# PEM转换为DER
openssl x509 -outform der -in server.crt -out server.der
# DER转换为PEM
openssl x509 -inform der -in server.der -out server.pem
# PEM转换为PKCS
openssl pkcs12 -export -out server.pfx -inkey server.key -in server.crt -certfile ca.crt
# PKCS转换为PEM
openssl pkcs12 -in server.pfx -out server.pem -nodes

证书校验

# 自签名证书
openssl verify server.crt
# 带CA校验
openssl verify -CAfile ca.crt server.crt

查看和测试服务器证书

# 查看服务端证书
openssl s_client -connect yourserver:443
# 保存服务端证书
openssl s_client -connect yourserver:443 server.crt
# 用证书启动一个测试服务器
openssl s_server -accept 443 -cert server.crt -key server.key -www

部署

分别以最常用的Apache和Nginx为例,其它WebServer请参考相关文档。

Apache

这里只介绍Apache2(以2.4为例)。

HTTPS的基本配置可以直接套用默认配置,只是要改一下证书文件的部分:

SSLEngine on
SSLCertificateFile  /path_to_ssl/server.crt
SSLCertificateKeyFile /path_to_ssl/server.key
SSLCertificateChainFile /path_to_ssl/server-ca.crt

其中server.crt和server.key就是前面说过的私钥和域名证书。

重点说一下server-ca.crt,这个就是前面谈到商业证书时提到的中间证书链(包括CA根证书)。对于Let’s Encrypt这样的免费证书,这个就是Let’s Encrypt的证书(见旧文),对于自签名证书,这一项可以去掉。

中间证书链的生成方法如下:

cat provider.crt provider-parent.crt root.crt > server-ca.crt

很简单,就是把那一堆证书串起来生成一个证书文件即可,不过需要注意顺序,从最低级的证书(你的域名证书的上一级)开始到最高级的CA根证书。

Apache从2.2.12开始支持SNI,可以为多个域名的虚拟主机使用各自独立的证书,用法与HTTP虚拟主机类似,只需要在每个虚拟主机配置里加上相应的证书配置即可。

需要注意的是:WinXP,JAVA6,Android 2.3等不支持SNI。

最后,如我在去年的旧文里所说,SSLv2/v3之类的协议和某些SSL加密算法已经不再安全,所以在没有特定的兼容性需要的情况下,需要配置禁用这些不安全的选项。

在全局配置(注意,不是单个虚拟主机配置里)里加上:

SSLProtocol TLSv1 +TLSv1.1 +TLSv1.2
SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:!DHE-RSA-AES128-GCM-SHA256:!DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:!DHE-RSA-AES128-SHA256:!DHE-RSA-AES128-SHA:!DHE-DSS-AES128-SHA256:!DHE-RSA-AES256-SHA256:!DHE-DSS-AES256-SHA:!DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA

以上协议和加密算法都是目前还安全的,并且提供了最大可能的兼容性。未来如果出现新的安全问题,请自行调整。

Nginx

基本上在旧文里都说过了,这里再总结一下。

相比Apache的配置,Nginx没有单独的中间证书链项目,所以是把中间证书链和域名证书串在一起作为完整的域名证书来用:

cat server.crt server-ca.crt > server.full.crt

配置HTTPS:

listen 443 ssl http2;
ssl_certificate "/path_to_ssl/server.full.crt";
ssl_certificate_key "/path_to_ssl/server.key";

注意:新版的Nginx不再支持ssl on指令,而是直接在listen指令后加上ssl,另外,更新的版本还可以支持http2,直接加上即可。

SNI使用和虚拟主机类似的方法配置。

全局安全配置:

ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers  ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:!DHE-RSA-AES128-GCM-SHA256:!DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:!DHE-RSA-AES128-SHA256:!DHE-RSA-AES128-SHA:!DHE-RSA-AES256-SHA256:!DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS;

配置完成后重启服务即可生效。

校验

不论是用Apache还是Nginx,都建议配置完HTTPS以后到SSL Labs验证一下安全性。

推送到[go4pro.org]