1. 引言
上一篇文章中,我们详细介绍了 SSL 协议与整个通讯流程。 那么,我们如何配置才能让我们自己的网站被浏览器鉴定为安全,并且从根本上保障通讯的安全性呢? 别着急,本文我们就来详细介绍如何配置我们自己的 https 服务。
2. 私钥与公钥的生成
2.1. openssl
我们可以通过开源的 openssl 工具来生成我们的私钥和公钥,openssl 是一个非常强大的开源套件,他包含三个部分:
- libcryto — 通用加密库,包含众多加密算法的实现
- libssl — ssl 机制的实现,用于实现 TLS/SSL 的功能
- openssl — 多功能命令行工具,可以用于加密或解密,甚至可以用来创建和吊销证书
有了 openssl,我们就可以轻松生成配置 ssl 所需的公钥和私钥文件了。
2.1.1. 安装
如果你使用的是 centos,执行下面命令即可:
yum install openssl yum install openssl-devel
如果你使用的是 ubuntu,执行下面的命令:
apt install openssl apt install libssl-dev
此外,你也可以到官网下载源码包编译安装: https://www.openssl.org/
2.2. 生成私钥
执行下面的命令即可生成私钥文件 ssl.key。
openssl genrsa -out ssl.key 2048
参数 2048 是秘钥的比特长度,2009年12月12日,编号为 RSA-768 的秘钥被成功分解,他的长度为 768 比特,1024 比特秘钥的安全性已经受到威胁,因此使用 2048 比特长度的秘钥目前是非常安全的,不建议生成 1024 比特长度的秘钥。
2.3. 生成证书请求csr
执行下面的命令生成包含公钥与服务信息的证书。
openssl req -new -key ssl.key -days 3650 -out ssl.csr
-days 参数是证书的有效期。
2.4. 一键生成上述的私钥与公钥文件
openssl 命令支持意见同时生成公钥与私钥文件:
openssl req -new -newkey rsa:2048 -sha256 -nodes -out test_com.csr -keyout test_com.key -subj "/C=CN/ST=Beijing/L=Beijing/O=website Inc./OU=Web Securi ty/CN=*.test.com"
完成这一步,就已经完成了我们的文件生成工作,如果你要让客户端新人,你必须有一个 CA 颁发的数字证书,到此你有两种选择:使用通用的 CA 认证机构颁发的证书或自己生成根证书与含链证书,具体请分别参考下面两部分中的对应部分。
3. 申请 CA 认证证书
根据我们的上一篇文章可以知道,整个信任链最重要的就是认证机构颁发的证书了。 我们可以找一个免费的 CA 机构,上传上面生成 csr 文件,按照 CA 的提示进行操作验证,最终获取到机构认证的数字证书,保存到服务器目录下。
4. 生成自己的根证书与含链证书
在免费 CA 认证机构中认证证书是最为方便的方式了,但有时,你不希望你的网站或接口被任意访问,因此不能让所有客户端都轻易获取到根证书,显然,在这样的情况下,通过 CA 生成数字证书就无法实现了,我们需要生成自己的根证书与含链证书。
4.1. 生成根证书私钥
我们要实现一个 CA,首先要生成 CA 的私钥,生成命令和过程上面已经介绍过,使用项目命令即可。
4.2. 生成根证书签发申请文件
执行下面的命令可以生成根证书:
openssl req -new -key ca/ca.key -out ca.csr
4.3. 签发根证书
执行下面的命令签发根证书:
openssl x509 -req -days 3650 -sha1 -extensions v3_ca -signkey ca.key -in ca.csr -out ca.crt
4.4. 签发服务端数字证书
执行下面的命令签发服务端数字证书:
openssl ca -in server.csr -out server.crt -cert ca.crt -keyfile ca.key
5. 证书的使用
在生成所有证书以后,我们只要在相应的客户端安装我们生成的 CA 根证书为信任机构,所有 CA 生成的数字证书都会在安装后被信任。 在 python 中,通过 requests 包方法众多 verify 参数传入证书文件地址即可:
代码语言:javascript复制requests.get('https://exaple.com', verify='ca.crt')
6. nginx 配置
如果你的网站是通过 nginx 做负载均衡的,那么只需要在 server 配置中增加下面的配置即可:
代码语言:javascript复制listen 443 default ssl;
ssl_certificate /etc/nginx/ssl/techlog/fullchain.crt;
ssl_certificate_key /etc/nginx/ssl/techlog/ssl.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
如同我们开始的图片所示,谷歌浏览器已经自动标记我们的网站为安全的了。
7. 配置 http 请求自动转发到 https
既然我们已经使用了 https 来保障传输的安全性,那么我们就应该废弃原有的 http 请求方式,但我们也不能直接拒绝所有 http 请求。 最好的方式,是通过返回自动跳转代码,让客户端可以自动跳转到 https 的新网站中。 之前 http 协议的介绍中,我们介绍了自动跳转的代码和他们的不同: HTTP 协议简介
主要有两种 code:
- 301 Moved Permanently — 永久性转移
- 302 Found — 临时跳转
此处应该使用的 301 永久性转移,浏览器等客户端会存储旧链接与新链接的对应关系,下次请求旧链接将直接跳转到新链接,而避免了额外的网络请求。 下面,我们就来介绍如何配置 nginx 来实现这一过程:
7.1. rewrite
我们通过 nginx rewrite 的 flag 参数就可以实现 301 跳转,具体可以参考此前的文章: nginx rewrite 规则的配置
代码语言:javascript复制server {
listen 80;
server_name domain.com;
rewrite ^(.*) https://$server_name$1 permanent;
}
7.2. return
nginx 配置的 return 指令可以指定返回数据的 code 等信息,我们只要显式指定 301 code 即可。
代码语言:javascript复制server {
listen 80;
server_name domain.com;
return 301 https://$server_name$request_uri;
}
7.3. error_page
除上述跳转的方式,nginx 也定义了一种错误码,用来强制浏览器跳转到对应的 https 链接,这个错误码就是 497,这是 nginx 的内置 HTTP 状态码,HTTP 协议中并没有定义这个状态码,nginx 会自动处理他并跳转。
代码语言:javascript复制server {
listen 80;
listen 443 ssl;
server_name domain.com;
ssl on;
ssl_certificate /etc/nginx/ssl/domain.com.crt;
ssl_certificate_key /etc/nginx/ssl/domain.com.crt;
# other
error_page 497 https://$server_name$request_uri;
}