问题
nginx配置自签名ssl证书,来支持https访问nginx,在浏览器中访问nginx时,提示有风险。而访问其他各大网站时,也是使用了https协议,为什么可以直接访问,而不提示有风险呢?
解疑
先从ssl证书说起。是否使用https协议或者说是否使用ssl认证,是后台网站服务器来决定的。如果想使用https协议,则在后台服务中配置ssl证书即可。配置了ssl证书后,浏览器访问网站服务,就要使用https协议。在这个过程中,浏览器会先获取到网站服务器中的证书信息,然后浏览器本身维护了一个受信任的证书列表。只要网站服务返回的证书在这个受信任的证书列表里面,那么说明这个服务是安全的,浏览器就直接访问到服务了。如果返回的证书没在受信任列表中,那么浏览器认为这个服务是不安全的,就会发出报警信息,不过用户可以手动选择信任此网站,继续访问服务。
由上面的描述可知,使用了ssl证书后,是浏览器为了安全起见,去验证服务器的证书是否信任,信任才能直接访问。大厂的网站的https协议浏览器没有发出报警,是因为大厂都使用了第三方授权的SSL证书,这些证书浏览器默认都是受信任的证书,所以直接就可以访问。但是第三方授权SSL证书一般都要收费才能获取。
而本项目中使用的证书,是自签名证书,浏览器受信任证书列表中没有它,所以就发出报警了。
上述说的是https单项认证,即浏览器认证后台服务证书。也可以开启双向认证,即浏览器认证服务器证书,服务器也认证浏览器证书。但是对于大众网站来说,一般都是单向认证即可。
解决
通过上面的描述可知,想要使自签名证书在浏览器中不报警,那么就要加入到浏览器信任列表中。网上搜了很多nginx生成证书并加入浏览器信任列表的方法,但大部分都不能跳过浏览器的报警。下面记录可以成功跳过浏览器报警的证书生成方式和配置方式。
使用java提供的工具进行生成。
第一步:
keytool -genkeypair -keyalg RSA -dname "CN=Demo" -alias server -keystore server.jks -keypass 123456 -storepass 123456 -ext SAN=dns:域名,ip:后端服务ip
生成server.jks文件。
第二步:
keytool -exportcert -file server.cer -alias server -keystore server.jks -storepass 123456
生成server.cer文件。
第三步:
keytool -importcert -file server.cer -alias server1 -keyalg client_trusk.jks -storepass 123456 -keypass 123456
输出如下:
输入是即可。
第四步:
keytool -importkeystore -srckeystore server.jks -destkeystore server-pkcs12.p12 -deststoretype PKCS12
输入相应的密码即可。生成server-pkcs12.p12文件。
第五步:
openssl x509 -inform der -in server.cer -out server-pem.pem
生成了server-pem.pem文件。
第六步:
openssl pkcs12 -nocerts -nodes -in server-pkcs12.p12 -out server.key
生成server.key文件。
第七步:
将server.key文件和server-pem.pem文件配置到nginx服务的config配置文件中,将server.cer文件安装在浏览器受信任列表中。这样,浏览器访问nginx就可以不再报警,直接访问了。
参考文章:Nginx证书配置:cer文件和jks文件转nginx证书.crt和key文件
(注意:参考文章方式有问题,按照参考文章配置出来的nginx无法让浏览器跳过报警,本博客对该文章进行了优化和纠错)
扩展
在上面的操作中,一共生成了如下几个文件:
而最终,只用到了其中的三个文件。那么这几个文件到底都是干啥的呢?具体可参考关于PEM, DER, CRT, CER,KEY等各类证书与密钥文件后缀的解释一文,这里只做一下简单记录。
在上述步骤中,第一步生成了jks文件,jks文件表示Java 密钥库. 同时包含证书和私钥。
第二步,在第一步生成的jks文件中,导出了cer文件。而cer文件是只包含证书,不保存私钥。一般Linux使用.crt后缀,.cer是windows后缀。因为jks中既包括私钥,也包括证书,所以第二步上讲证书提取出来成了cer文件。而这个cer文件,也是要最后在浏览器中安装到受信任列表的证书文件。
第三步也是对cer证书的一个操作,让这个证书受信任之类的,固定操作,记住即可。
第四步是将第一步生成的jks文件,转换成了p12格式的文件。p12文件是二进制格式,同时包含证书和私钥。可以看出是对jks文件换了一种格式而已,p12还包含证书和私钥。
第五步将cer证书转换成了pem格式。pem文件是使用Base64 ASCII编码后的纯文本文件。不管是证书还是密钥,只要是pem格式,使用文本编辑器打开都是类似的样子,一串冗长的字符串。可以看出,pem只是一种文件格式,证书和私钥,都可以转成pem格式。这里是将证书转成了pem格式。
第六步将p12文件转换成了.key文件,.key文件是私钥,与证书一一配对。即将p12文件中的私钥提取出来了。
第七步就是将.key文件(私钥)和.pem文件(证书)配置到了nginx中,将.cer文件(windows格式证书)配置到了浏览器信任列表中,这样就跳过了浏览器报警。
公钥/私钥/证书三者的区别
在ssl证书中,一会有公钥,一会儿有私钥,一会儿有证书,完全搞蒙蔽了。下面来梳理一下:
首先,私钥是放在服务器中的。如在上面的nginx中,将.key文件(私钥)放在了服务器中。
证书,是配置在服务器中的ssl证书,如nginx中的pem文件就是证书,证书中也有公钥。当浏览器访问ssl协议的网站时,会获取到网站证书,同时也会获取到公钥。然后浏览器拿着获取到的公钥,与网站进行传输,然后到服务器后,服务器通过私钥对数据进行解密。所以https就采用了非对称加密方式保证了数据安全性。
在SpringBoot项目配置https访问单项认证谷歌有效证书一文中,在后台只配置了一个.keystore文件。是因为.keystore文件,既是证书文件,也含有公钥,也含有私钥。