文章目录
配置HTTPS站点
前提
- 一个已认证的域名(本文为
wantp.xyz
) Web
服务器(本文为NGINX 1.17.6
)- 已部署的HTTP站点(本文为
http://www.wantp.xyz
)
HTTPS简介
由于 HTTP
协议在网络上是以明文传输的,使得HTTP请求在被劫持后信息完全暴露,很容易被不法之徒利用。为加强传输过程的安全性,对传输的信息进行加密就变得很有必要,SSL/TLS
协议应运而生。SSL/TLS
协议是运行在 TCP
和 HTTP
中间的,在 TCP
三次握手后,SSL/TLS
验证客户端和服务端的真实性并协商加密方式,后续的HTTP
都以协商好的加密方式传输并在服务端解密,这样即使传输被劫持,黑客拿到的是加密后的信息,很难加以利用。
更详细的 SSL/TLS
工作原理可以从官方文档或者其他文章学习,本文重点在于介绍如何配置一个 HTTPS
站点。
SSL/TLS
协议是SSL
协议和TLS
协议的统称,TLS
是SSL
的升级版。由于SSL
存在很多的已知安全漏洞,升级到SSLv3
依然没能解决问题,因此重新设计了TLS
作为SSL
的替代。一般如果不是为了兼容较古老的浏览器(如IE6),HTTPS
站点建议都只支持TLS
。
SSL/TLS
是通过浏览器的证书数字签名和服务器的SSL
证书来验证客户端和服务端的真实性的,因此要配置HTTPS
站点,第一步需要准备好SSL
证书。
一、获取SSL证书
SSL
证书一般是跟权威的CA厂商(Symantec
、GeoTrust
、TrustAsia
等)购买,一般价格都比较昂贵(对于个人、普通站点和小企业而言)。
常见 SSL
证书有三种类型:
域名型SSL证书(DV SSL):信任等级普通,只需验证网站的真实性便可颁发证书保护网站;
企业型SSL证书(OV SSL):信任等级强,须要验证企业的身份,审核严格,安全性更高;
增强型SSL证书(EV SSL):信任等级最高,一般用于银行证券等金融机构,审核严格,安全性最高,同时可以激活绿色网址栏。
DV SSL
的证书价格相对便宜,也有不少免费的,很适合个人网站或者小企业。
国内又拍、腾讯、阿里等厂商都可以申请为期一年的免费 DV
证书。
不过免费的DV SSL
证书开源的 Let‘s Encrypt 可能是更好的选择, Let‘s Encrypt 可以颁发3个月有效期的证书,并且可以实现自动续签。
还有一种完全不依赖第三方厂商的方式就是:自签发证书,虽然可以实现https,但是自己颁发的证书是不会得到浏览器的认可的。下面分别介绍自签发证书和Let‘s Encrypt
免费证书。
现在HTTP
站点在主流浏览器上都会提示不安全。
1. 自签发证书
购买或申请免费证书如果都觉得很麻烦,还有一个选择是自签发证书。不过自己签发的证书是不被信任的,用于站点时主流浏览器都会提示这是一个不安全的链接。但是对一些强制需要HTTPS
但会通过浏览器访问来访问的功能还是可以用的。
1.1 生成私钥
$ openssl genrsa -des3 -out ssl.key 2048
生成了一个rsa
私钥,des
算法,2048
长度,长度低于2048
在新版的NGINX
会报秘钥长度太短的错误
上述命令会要求输入一个密码
想简化后续的调用可以去掉密码
$ openssl rsa -in ssl.key -out ssl.key
1.2 生成CSR(证书签名请求)
$ openssl req -new -key ssl.key -out ssl.csr
请求需要依次输入国家、地区、城市、组织、组织单位、Common Name(与要部署证书的域名一致)和Email
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:ShangHai
Locality Name (eg, city) []:ShangHai
Organization Name (eg, company) [Internet Widgits Pty Ltd]:wantp
Organizational Unit Name (eg, section) []:wantp
Common Name (e.g. server FQDN or YOUR name) []:wantp.xyz
Email Address []:zhangrongwang798@gmail.com
1.3 生成证书
$ openssl x509 -req -days 3650 -in ssl.csr -signkey ssl.key -out ssl.crt
以上命令签发了有效期为3650天的crt
证书。
1.4 配置web服务器
Web
服务器配置ssl
,web服务器配置更详细说明请参考 Web服务配置
/etc/nginx/conf.d/wantp.xyz.conf
server {
listen 443 ssl; # 监听443端口 开启ssl
server_name www.wanp.xyz; # 域名
root /var/www/wantp.xyz/; # 项目根目录
index index.html index.php;
ssl_certificate "/root/ssl/wantp.xyz/ssl.crt"; # SSL证书路径
ssl_certificate_key "/root/ssl/wantp.xyz/ssl.key"; # SSL证书私钥路径
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # 支持的协议
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; # 加密套件
ssl_prefer_server_ciphers on;
... # 项目其它配置
}
重启 nginx
服务
$ sudo nginx -s reload
访问https://www.wantp.xyz
浏览器会有红色不安全提示,并且不能直接访问到站点。需要我们信任链接,点击继续前往,站点就能访问了。
2. Let’s Encrypt免费证书
Let's Encrypt
颁发的证书是浏览器信任的,不会像我们自己签发的会有不安全的提示,对于需要提供网页服务的站点来说是一个更好的选择。
Let's Encrypt
使用 Certbot
来实现证书的发布和自动续签。
2.1 安装Certbot
访问 Certbot 的官方网站,选择 Web
服务器和操作系统,
会有相应的安装、使用说明,不同系统安装过程有些许差别,可能需要先安装一些依赖库,按照说明一步步安装就好了
2.2 生成证书
Certbot
安装成功后就可以生成证书了,有两种方式
生成证书并部署并自动部署到Web
服务器
$ sudo certbot --nginx
只是生成证书,自己手动部署,我们选用此方式
$ sudo certbot certonly --nginx
上述命令会检测web服务的配置,通过交互选择需要颁发证书的网站
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: wantp.xyz
2: www.wantp.xyz
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel): 1 2
成功后会生成证书和对应的key
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/wantp.xyz/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/wantp.xyz/privkey.pem
Your cert will expire on 2020-03-02. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
2.3 配置web服务器
配置的证书和key的路径
/etc/nginx/conf.d/wantp.xyz.conf
server {
listen 443 ssl; # 监听443端口 开启ssl
server_name www.wanp.xyz; # 域名
root /var/www/wantp.xyz/; # 项目根目录
index index.html index.php;
ssl_certificate "/etc/letsencrypt/live/wantp.xyz/fullchain.pem"; # SSL证书路径
ssl_certificate_key "/etc/letsencrypt/live/wantp.xyz/privkey.pem"; # SSL证书私钥路径
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # 支持的协议
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; # 加密套件
ssl_prefer_server_ciphers on;
... # 项目其它配置
}
重启 nginx
服务器
$ sudo nginx -s reload
再次访问https://www.wantp.xyz,链接变成了加锁的安全标识
2.4 自动续期
出于安全考虑颁发的正式有效期为90天,每三个月都手动去签发一次证书会很麻烦,忘记在有效期内续签还可能导致网站访问出问题。因此Certbot
还提供了自动续签的功能。
执行证书更新指令,如果证书在30天内到期就会续订,否则不会进行任何操作
$ sudo certbot renew --dry-run
命令执行后,可以在以下计划任务中看到相关的定时任务,不同系统有差别
/etc/crontab/ 或 /etc/cron.*/* 或 systemctl list-timers
Debian 10
在/etc/cron.d/certbot
中查看
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(43200))' && certbot -q renew
可以看到每天执行两次 renew
检查
证书自动续期配置好了就不用担心证书过期的问题了
二、Web服务器配置
基础配置
server {
listen 443 ssl; # 监听443端口 开启ssl
server_name www.wantp.xyz; # 域名
root /var/www/wantp.xyz/; # 项目根目录
index index.html index.php;
ssl_certificate "/etc/letsencrypt/live/wantp.xyz/fullchain.pem"; # SSL证书路径
ssl_certificate_key "/etc/letsencrypt/live/wantp.xyz/privkey.pem"; # SSL证书私钥路径
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # 支持的协议
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; # 加密套件
ssl_prefer_server_ciphers on;
... # 项目其它配置
}
加密套件说明
1、最大兼容性(兼容IE6)
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH;
2、安全与兼容同时兼顾(参考阿里云)
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
3、最大安全性(仅兼容主流浏览器)
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256::!MD5;
域名重定向的配置
HTTPS
站点配置好后,我们往往希望用户永远访问的是我们的 HTTPS
站点,这时候需要对 HTTP
的站点做些处理,将HTTP
请求都重定向到HTTPS
上,例如将http://xyz.com
、http://www.xyz.com
都重定向到 https://www.xyz.com
上。
我们通过配置 web
服务器的重定向实现
server {
listen 80;
server_name wantp.xyz www.wantp.xyz;
return 307 https://www.wantp.xyz$request_uri;
}
重定向也可以通过 rewrite
实现,但是并不推荐,参考文档
处理 rewrite
时需要匹配正则表达式,这往往意味着更多的消耗。
HSTS
每次访问 http://www.abc.com
都会先发起一个 Http
请求然后重定向到 Https
。这个过程中存在一个风险,就是 Http
请求可能被劫持,导致后面的重定向不安全。通过配置 HSTS
可以让浏览器在有效期内自动将 Http
请求处理成 Https
请求而不是通过发起 Http
请求来重定向。
配置HSTS
很简单,只需要添加一个 Strict-Transport-Security header
头即可
server {
...
index index.html index.php;
add_header Strict-Transport-Security "max-age=31536000"; # HSTS,有效期为31536000秒
ssl_certificate "/home/ssl/abc/ssl.pem"; # SSL证书路径
...
}
要注意,即使配置了 HSTS
也还是存在第一次HTTP请求被劫持的风险,但是后续的请求都不会通过 HTTP
,风险已经大大的降低了。