Nginx 配置 SSL 证书开启 HTTPS 教程
一、HTTPS 是什么?
超文本传输安全协议(缩写:HTTPS,英语:Hypertext Transfer Protocol Secure)是超文本传输协议和SSL/TLS的组合,用以提供加密通讯及对网络服务器身份的鉴定。HTTPS连接经常被用于万维网上的交易支付和企业信息系统中敏感信息的传输。
HTTPS 目前已经是所有注重隐私和安全的网站的首选,随着技术的不断发展,HTTPS 网站已不再是大型网站的专利,所有普通的个人站长和博客均可以自己动手搭建一个安全的加密的网站。开启 HTTPS 有利于提升网站在搜索引擎中的排名。
如果一个网站没有加密,那么你的所有帐号密码都是明文传输。可想而知,如果涉及到隐私和金融问题,不加密的传输是多么可怕的一件事。
二、HTTP 和 HTTPS 比较
HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。
HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
HTTPS协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。
三、使用 OpenSSL 生成 SSL Key 和 CSR
由于只有浏览器或者系统信赖的 CA 才可以让所有的访问者通畅的访问你的加密网站,而不是出现证书错误的提示。
OpenSSL 在 Linux、OS X 等常规的系统下默认都安装了,因为一些安全问题,一般现在的第三方 SSL 证书签发机构都要求起码 2048 位的 RSA 加密的私钥。
同时,普通的 SSL 证书认证分两种形式,一种是 DV(Domain Validated),还有一种是 OV (Organization Validated),前者只需要验证域名,后者需要验证你的组织或公司,在安全性方面,肯定是后者要好。
无论你用 DV 还是 OV 生成私钥,都需要填写一些基本信息,这里我们假设如下:
- 域名,也称为 Common Name,因为特殊的证书不一定是域名:example.com
- 组织或公司名字(Organization):Example, Inc.
- 部门(Department):可以不填写,这里我们写Web Security
- 城市(City):Beijing
- 省份(State / Province):Beijing
- 国家(Country):CN
- 加密强度:2048 位,如果你的机器性能强劲,也可以选择 4096 位
按照以上信息,使用 OpenSSL 生成 key 和 csr 的命令如下
1 2 |
openssl req -new -newkey rsa:2048 -sha256 -nodes -out example_com.csr -keyout \ example_com.key -subj "/C=CN/ST=Beijing/L=Beijing/O=Example Inc./OU=Web Security/CN=example.com" |
PS:如果是泛域名证书,则应该填写*.example.com
你可以在系统的任何地方运行这个命令,会自动在当前目录生成example_com.csr和example_com.key这两个文件
接下来你可以查看一下example_com.csr,得到类似这么一长串的文字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
-----BEGIN CERTIFICATE REQUEST----- MIICujCCAaICAQAwdTELMAkGA1UEBhMCQ04xEDAOBgNVBAgTB0JlaWppbmcxEDAO BgNVBAcTB0JlaWppbmcxFTATBgNVBAoTDEV4YW1wbGUgSW5jLjEVMBMGA1UECxMM V2ViIFNlY3VyaXR5MRQwEgYDVQQDEwtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBAPME+nvVCdGN9VWn+vp7JkMoOdpOurYMPvclIbsI iD7mGN982Ocl22O9wCV/4tL6DpTcXfNX+eWd7CNEKT4i+JYGqllqP3/CojhkemiY SF3jwncvP6VoST/HsZeMyNB71XwYnxFCGqSyE3QjxmQ9ae38H2LIpCllfd1l7iVp AX4i2+HvGTHFzb0XnmMLzq4HyVuEIMoYwiZX8hq+kwEAhKpBdfawkOcIRkbOlFew SEjLyHY+nruXutmQx1d7lzZCxut5Sm5At9al0bf5FOaaJylTEwNEpFkP3L29GtoU qg1t9Q8WufIfK9vXqQqwg8J1muK7kksnbYcoPnNgPx36kZsCAwEAAaAAMA0GCSqG SIb3DQEBBQUAA4IBAQCHgIuhpcgrsNwDuW6731/DeVwq2x3ZRqRBuj9/M8oONQen 1QIacBifEMr+Ma+C+wIpt3bHvtXEF8cCAJAR9sQ4Svy7M0w25DwrwaWIjxcf/J8U audL/029CkAuewFCdBILTRAAeDqxsAsUyiBIGTIT+uqi+EpGG4OlyKK/MF13FxDj /oKyrSJDtp1Xr9R7iqGCs/Zl5qWmDaLN7/qxBK6vX2R/HLhOK0aKi1ZQ4cZeP7Mr 8EzjDIAko87Nb/aIsFyKrt6Ze3jOF0/vnnpw7pMvhq+folWdTVXddjd9Dpr2x1nc y5hnop4k6kVRXDjQ4OTduQq4P+SzU4hb41GIQEz4 -----END CERTIFICATE REQUEST----- |
这个 CSR 文件就是你需要提交给 SSL 认证机构的,当你的域名或组织通过验证后,认证机构就会颁发给你一个example_com.crt
而example_com.key是需要用在 Nginx 配置里和example_com.crt配合使用的,需要好好保管,千万别泄露给任何第三方。
四、Nginx 配置 HTTPS 网站以及增加安全的配置
前面已经提到,你需要提交 CSR 文件给第三方 SSL 认证机构,通过认证后,他们会颁发给你一个 CRT 文件,我们命名为example_com.crt
同时,为了统一,你可以把这三个文件(example_com.crt、example_com.key、example_com.csr)都移动到/etc/ssl/private/目录。
然后可以修改 Nginx 配置文件
1 2 3 4 5 6 7 8 9 10 11 |
server { listen 80; listen [::]:80 ssl ipv6only=on; listen 443 ssl; listen [::]:443 ssl ipv6only=on; server_name example.com; ssl on; ssl_certificate /etc/ssl/private/example_com.crt; ssl_certificate_key /etc/ssl/private/example_com.key; } |
检测配置文件没问题后重新读取 Nginx 即可
nginx -t && nginx -s reload
但是这么做并不安全,默认是 SHA-1 形式,而现在主流的方案应该都避免 SHA-1,为了确保更强的安全性,我们可以采取迪菲-赫尔曼密钥交换
首先,进入/etc/ssl/certs目录并生成一个dhparam.pem
1 2 |
cd /etc/ssl/certs openssl dhparam -out dhparam.pem 2048 # 如果你的机器性能足够强大,可以用 4096 位加密 |
生成完毕后,在 Nginx 的 SSL 配置后面加入
1 2 3 4 5 6 7 |
ssl_prefer_server_ciphers on; ssl_dhparam /etc/ssl/certs/dhparam.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DHE+AES128:!ADH:!AECDH:!MD5; keepalive_timeout 70; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; |
同时,如果是全站 HTTPS 并且不考虑 HTTP 的话,可以加入 HSTS 告诉你的浏览器本网站全站加密,并且强制用 HTTPS 访问
1 2 3 |
add_header Strict-Transport-Security max-age=63072000; add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; |
同时也可以单独开一个 Nginx 配置,把 HTTP 的访问请求都用 301 跳转到 HTTPS
1 2 3 4 5 6 |
server { listen 80; listen [::]:80 ssl ipv6only=on; server_name example.com; return 301 https://example.com$request_uri; } |
五、证书链
ssl证书有根证书直接签发,也用根证书签发的二三级证书签发证书,所以如果你的证书不是由顶级根证书直接签发的情况下,你需要补全中间的二三级证书和根证书到证书链文件里。顺序是:你的ssl证书+中间证书+根证书。
通常来说浏览起会内置顶级知名根证书,对于中间证书可能会不内置,例如安卓端会不认中间证书颁发的ssl证书证书,因为安卓没有内置这些中间证书,需要你把这些证书拼接到一个证书链文件中发给客户端。
1 |
cat nginx.crt bundle.crt > nginx.chain.crt |
在 Nginx 配置里使用 nginx.chain.crt 即可解决不识别证书的问题,证书的顺序不能反了,反了会报错:
1 2 3 |
SSL_CTX_use_PrivateKey_file(" ... /www.example.com.key") failed (SSL: error:0B080074:x509 certificate routines: X509_check_private_key:key values mismatch) |
因为 nginx 中的私钥 key 是和证书链中的第一个证书验证,如果顺序反了,就变成和bundle.crt配对。
六、一个IP多个证书
TLS SNI support enabled
在一个主机(IP)上配置多个域名,使用虚拟主机(virtual host)就可以解决了。但是申请TLS证书的时候,是绑定了具体的域名和IP地址。建立TLS连接的时候,服务器要下发哪个证书呢?
等等,证书明明和域名绑定,都知道了域名,为什么会有选择选择证书的问题?
那是因为,域名是http的概念。client和server先建立了tcp连接,再经过TLS握手,才能实现https通信。在最初,这个过程,是没有域名的概念的!
为了解决单个主机部署多个TLS证书的问题,带来了TLS的SNI扩展。
nginx开启TLS SNI ,只需要在编译时打开--with-openssl编译选项,具体可以参考nginx安装。
检查nginx是否支持TLS SNI,执行 nginx -V
1 2 3 4 5 |
[root@www ~]# /usr/local/nginx/sbin/nginx -V nginx version: nginx/1.18.0 built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC) built with OpenSSL 1.1.1g 21 Apr 2020 TLS SNI support enabled |
参考:https://www.cnblogs.com/chjbbs/p/5748369.html