之前写的关于nginx的内容都是http的,现在轮到https上场了。其实https和http的不同是在于端口、证书和秘钥,其他基础配置都是相同的,这一篇我们来看看如何生成https证书和私钥、https实现的流程和相关的使用注意事项。当然这个证书和私钥是我们自己生成的,没有通过权威机构认证,在浏览器请求显示的时候会有提醒。要是想要正式的证书和秘钥,可以到相关机构去购买,有点耗银子。有兴趣的可以去找找。
1. https实现过程
https在请求的时候会从nginx端下载https证书,然后根据证书内的公钥来对请求的内容进行加密,加密完成后请求到nginx,nginx根据私钥来解密,将解密后的内容通过http请求发到对应tomcat应用(当然是不仅限于tomcat)。具体流程看下面的图示:
看了这张图后,发现以前我对https的理解是不对的。使用公钥加密的内容并不是请求的数据信息,而是一个随机的秘钥。然后根据秘钥对称加密请求数据,nginx通过秘钥来进行对称解密得到请求数据,最终以http的方式转发到对应的服务。
2. https证书、私钥生成
这种生成方式只能说自己玩玩可以,公司内的产品上线一般都不会这么用。我记得在12306没有改版之前使用的https就是自己生成的,导致请求不会直接进入官网首页,而是给出警告页面,需要进行一步信任操作才能进入。12306敢在线上使用那是因为它NB(有本事你就别用)。如果换一个初创的公司这样做,估计坟头上的草已经三丈高啦。
生成过程:
创建服务器私钥
openssl genrsa -des3 -out server.key 1024
这一步需要输入口令,可以理解为是密码,输入两次。
创建签名请求的证书(CSR)
openssl req -new -key server.key -out server.csr
这一步需要输入内容很多,但是大部分可以省略,首先输入口令,然后输入国家名(cn),然后输入城市名(sh),咱们都是中国人,都写cn就可以,城市名根据你所在城市来写。这两项完成输入后还有很多需要填的,直接回车,一直到结束即可。
加载SSL支持的nginx并使用删除私钥是除去必须的口令
openssl rsa -in server.key -out server_nopass.key
这一步是除去口令的验证,减少输入口令的麻烦。
最后标记证书使用上述私钥和CSR
openssl x509 -req -days 365 -in server.csr -signkey server_nopass.key -out server.crt
这一步正式生成证书,将在客户端和nginx建立连接初期提供给客户端。
注意:在机器中没有安装nginx或者安装nginx没有包含https模块的,在生成证书、私钥过程可能会受一点阻塞。查看nginx是否已经安装https模块的命令:
/usr/local/nginx/sbin/nginx -V
这里V是大写的,另外/usr/local/nginx/sbin/nginx
会根据你nginx安装目录的不同而不同。然后会看到如下的输出内容:
nginx version: nginx/1.13.10
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-23) (GCC)
built with OpenSSL 1.0.1e-fips 11 Feb 2013
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module
看configure arguments
信息,包含--with-http_ssl_module
即为安装了https模块,如果没有需要对nginx重新配置、编译、安装,这个就不多说了,具体怎么做可以参考下面推荐文章的第一篇。
3. nginx.conf内https的配置
其实配置很简单,除了加上端口变化、证书和私钥的信息,其他都是和http配置相同的。配置如下:
server {
listen 443 ssl;
server_name blog.itcrud.com;
ssl_certificate /usr/local/https/server.crt;
ssl_certificate_key /usr/local/https/server_nopass.key;
location / {
# ……
}
}
端口由之前的80
换成443 ssl
,然后加上ssl_certificate
和ssl_certificate_key
指定证书和私钥的存储位置。
4. http跳转https
如果你们平时使用百度细心的话会发现,当输入http://www.baidu.com
的时候,浏览器上的地址会自动变换成https://www.baidu.com
。通过浏览器的控制台可以看到当请求http的百度时会返回一个状态码307 Internal Redirect
,然后响应头里面的location对应的地址是https的百度地址,接着浏览器会根据这个https地址重新请求打开百度首页。这是就是在nginx内动了手脚。配置如下:
server {
listen 80;
server_name blog.itcrud.com;
rewrite ^/ https://blog.itcrud.com redirect; # 通过rewrite重定向
}
是不是很简单。
5. http和https的混用问题
在微服务里面,有很多子模块,每个子模块都是独立的,域名也是独立的。有时候在展示一个页面的内容,需要发送多个ajax
请求到多个子模块中获取数据,然后渲染到页面上。但是这里存在一个问题就是http和https混用。
有以下两种情况:
- 当主页面是使用的http请求,但是请求子模块是用的https,这样会导致请求子模块失败,因为这样是不支持的。建议在使用https的时候做好规划,不要盲目,有可能会导致项目的bug,解决方案就是把所有子模块都改成使用https。
- 当主页面是使用的https请求,子模块使用的是http,这个是不受影响。但是从安全角度来考虑,还是建议都换成使用https。
注意:这个混用的问题我们是建立在跨域问题已经解决的前提下说的。