背景:
之前项目都是为集团内部提供服务的,很多接口都是内网访问,网络安全方面考虑不多。但是随着业务发展,可能要对外提供互联网服务了,一些安全方面的因素也要逐步考虑计划。
这次,就从最基本的域名安装SSL证书开始,将http协议升级为https协议。
一、购买申请SSL证书
直接进阿里云官网购买证书,暂时选择免费版本测试。
购买后进入证书控制台,需要进行证书申请。
需要注意的是我们的ssl证书是和域名绑定的,所以需要提供域名。并且阿里云免费证书只支持绑定一个域名,收费版支持多个域名(通配符)
关于这个域名验证方式,它提示我绑定的域名已在阿里云的云解析服务中,这个其实是假的,我的域名是在腾讯云买的,在阿里云并没有云解析服务。
但是没关系,我们依旧可以选择自动DNS验证,以及csr生成方式也是选择自动。
上面的DNS解析验证比较关键,需要我们去域名解析处配置,我是腾讯云买的域名,所以我去腾讯云解析配置。
新增一条域名解析策略,将记录类型:TXT、主机记录:_dnsauth、记录值:201911060000000ajcb4f4配置完毕后,等其生效。
然后去阿里云证书申请处点击验证,会提示验证成功。
之后就可以看到我们的证书变成已签发的了。
然后就可以下载证书了。我选择的是Nginx版本证书。
下载到本地的压缩文件包解压后包含:
.crt文件:是证书文件,crt是pem文件的扩展名。
.key文件:证书的私钥文件(申请证书时如果没有选择自动创建CSR,则没有该文件)。
二、通过nginx配置SSL证书
先按阿里云的nginx证书帮助文档操作:
1.在Nginx的安装目录(我的是/usr/local/nginx
默认目录,注意不是解压目录)下创建cert
目录,并且将下载的全部文件拷贝到cert目录中。如果申请证书时是自己创建的CSR文件,请将对应的私钥文件放到cert目录下并且命名为a.key;
2.添加nginx.conf
配置:
server {
listen 443;
server_name localhost;
ssl on;
root html;
index index.html index.htm;
ssl_certificate cert/a.pem;
ssl_certificate_key cert/a.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {
root html;
index index.html index.htm;
}
}
然后nginx -s reload
重启,就发现报错了,在error.log
中:
2019/11/07 15:21:41 [emerg] 6649#0: unknown directive "ssl" in /usr/local/nginx/conf/nginx.conf:115
我开始以为是cert文件路径不对(其实确实不对。。但不是报错的主要原因),然后尝试各种路径变幻相对绝对都还是报错。
我只能认为我的nginx默认没有安装ssl模块了。然后去尝试安装,发现果然如此。
nginx安装配置SSL模块:
1.先确保linux服务器安装了ssl组件:
yum -y install openssl openssl-devel
2.再去nginx解压目录(不是安装目录)下执行:
./configure --with-http_ssl_module
注意:此处如果你之前安装nginx时不是用的默认配置,那此处还得添加当时的其他各种configure
3.执行make编译
4.将原来/usr/local/nginx/sbin/
下的nginx执行文件备份一下,以防万一
cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak
然后将解压目录下新的编译后的nginx文件复制到安装目录原位置
cp objs/nginx /usr/local/nginx/sbin/nginx
5.测试 nginx配置是否正确
/usr/local/nginx/sbin/nginx -t
发现报错方式换了:
BIO_new_file("/usr/local/nginx/conf/cert/a.pem") failed (SSL: error:02001002:
system library:fopen:No such file or directory:fopen('/usr/local/nginx/conf/cert/a.pem','r') error:2006D080:BIO routines:BIO_new_file:no such file)
哦 ~ 原来路径错误是这样报错的呀!
可以发现,我们nginx.conf里配置的ssl_certificate cert/a.pem;
其实运行时是去/usr/local/nginx/conf/cert/a.pem
下找的文件,即以nginx.conf所在的conf目录为相对路径,这也符合常理。
那么阿里云这个帮助文档里写的 在Nginx的安装目录下创建cert目录
是啥意思,根本不能匹配上nginx.conf里的配置嘛?!
算了,不计较啥了,我们重新将/usr/local/nginx下的cert目录移动到/usr/local/nginx/conf下,再重启nginx,发现成功了。
三、将以前的http请求重定向到https
下面问题来了,配置好 https后,我们以什么方式访问才能跳转 https?之前的 http路径都要怎么处理?浏览器会如何切换?
测试后发现:
1.如果我们在浏览器中直接输入aaa.com
,其实会自动去跳转到http://aaa.com
,还是80端口的普通http流量
2.我们输入https://aaa.com
,这下成功利用到了ssl证书,符合期望
3.我们输入http://aaa.com:443/
行么,这种方式其实就是强行将http流量转移到https,会导致400错误,所以这条路也行不通
400 Bad Request
是由于明显的客户端错误(例如,格式错误的请求语法,太大的大小,无效的请求消息或欺骗性路由请求),服务器不能或不会处理该请求。
所以,我们或许需要将http请求都重定向到https?
如何重定向呢,用常用的proxy_pass
么?
server {
listen 80;
server_name localhost;
location / {
proxy_pass https://localhost/;
}
}
发现依旧是跳转到:http://aaa.com/
,并不行。而且多次尝试不同写法后还是不行。
我们放弃proxy_pass试试return
:
server {
listen 80;
server_name localhost;
location / {
return https://localhost/;
}
}
发现302重定向到了https://localhost/
,并没有自动将localhost转化为域名,这样也不行。
至于为啥使用return,可以看看nginx官网的wiki:
所以我们直接写域名:
server {
listen 80;
server_name localhost;
location / {
return https://aaa.com/;
}
}
发现OK!
我们观察下百度是怎么做的:
清除缓存后 (F12勾选 disable cache
),浏览器输入baidu.com
:
看来方式和我们差不多。都是从80端口302重定向到443的https端口。
四、要考虑的还有很多
所以,这么简单就完成了https的升级吗?
em,这是我阿里云的个人机器,没有啥项目运行,确实很随意。
但是我们真正的业务环境是比较复杂的,项目可能涉及多台服务器,每个服务器上可能有多个项目,这些项目也可能属于不同项目组、不同业务,但是却共用同一个Nginx服务器。
同一个nginx里可能配置了复杂的策略,其中有静态资源映射、负载均衡、各种维度的请求转发等。我们要将哪些http请求重定向到https?改造的过程中会不会对其他东西产生干扰?
所以,这里一定要深思熟虑,尽量减少不必要的麻烦。