原理
稍微懂点HTTPS原理的都知道,TLS提供机密性、完整性、真实性、身份验证…
不管是双sp里还是平时的实践中,耳熟能详的就是机密性,用非对称协商会话秘钥,在用会话秘钥加密会话
那么真实性和身份验证体现在哪?
身份验证,也就是认证,也就是验证你就是你,这里就要看是单向还是双向了
如果是单向,那默认指客户端验证服务器,也就是我们安全设计里面的最低要求,有公网的就需要使用HTTPS,证书绑定了域名的话,用IP访问会弹框【不安全】,必须信任才能继续,或者使用非授权/信任CA签发的服务器证书,也是会弹框【不安全】,这个弹框【不安全】,是专门指客户端验证服务器的过程
如果是双向,则是在单向也就是客户端验证服务器的基础上,加上服务器验证客户端。为什么要这么做?可以试想一下,如果我们的系统只想让指定客户访问,那么我们又没有Ukey,就很适合这种方式,另一种白名单嘛
附图:单向SSL中,非授权/信任CA签发的证书,或者授权/信任CA签发的证书,但是证书绑定域名,非要用IP访问,必须点高级,信任站点,才能访问,这个就相当于手动信任/认证
顺便说一下SSL和TLS的关系吧
先有的SSL,然后慢慢迭代TLS取代了SSL,在SSL 3.0之后,出现了TLS 1.0,TLS 1.0所以可以理解为SSL 3.1,不过目前安全的TLS版本是1.2和1.3,或许只是习惯,我们才会经常说双向SSL、SSL VPN…
nginx
单向SSL没什么好说的,我们主要就是要说双向SSL
单向SSL所需要的就只是服务器的证书,双向SSL涉及到的就是CA证书和客户端证书,并校验客户端证书,一定要把这两者分开,明白原理,我们就来实现
参考
https://www.jianshu.com/p/59ecf0120048
在安装openssl的linux下执行CA证书、服务器证书、客户端证书的生成,如果比较熟练了,可以直接把命令汇总章节中,生成CA、客户端、服务器证书的命令直接合起来写成个shell,一键生成
生成自签CA证书
生成CA的私钥文件
openssl genrsa -out ca.key 2048
生成CA证书,-subj参数可以免去交互式
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt -subj "/C=CN/O=People's Republic of China/CN=China CA"
通过openssl工具查看CA证书的内容
openssl x509 -text -noout -in ca.crt
生成自签服务器证书
-subj 参数很重要,其中/CN要填写具体的域名,要与nginx的server_name匹配上。
chrome浏览器对证书很严格,证书必须要有SAN(Subject Alternative Name)。
v3_req表示生成是X.509 v3和SAN的证书,-extfile和-extensions这两个参数是可选的,如果没有这两个参数,那证书就是没有SAN的,推荐加上这两个参数。
生成服务器的私钥文件
openssl genrsa -out server.key 2048
生成服务器的证书签发文件,即csr后缀的文件
openssl req -new -key server.key -out server.csr -subj "/C=CN/O=People's Republic of China/CN=example.com"
使用CA签发服务器证书,这里要注意一下,看看openssl的安装路径,我的配置就在这里/etc/pki/tls/openssl.cnf,不知道在哪的也可以find搜一下
openssl x509 -req -in server.csr -out server.crt -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 -extfile <(sed "/\[ v3_req \]/ a\subjectAltName = @alt_names" /etc/pki/tls/openssl.cnf <(printf "\n[alt_names]\nDNS.1=example.com\nDNS.2=www.example.com")) -extensions v3_req
通过openssl工具查看服务器证书的内容
openssl x509 -text -noout -in server.crt
生成客户端证书
客户端证书步骤跟服务器证书一样,只是参数不一样。
生成客户端的私钥文件
openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr -subj "/C=CN/O=People's Republic of China/CN=Private certificate assigned to Tom"
使用CA签发客户端证书
openssl x509 -req -in client.csr -out client.crt -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650
导出p12格式的
openssl pkcs12 -export -clcerts -out client.p12 -in client.crt -inkey client.key
温馨提示:不需要密码就按回车键。
通过openssl工具查看客户端证书的内容
openssl x509 -text -noout -in client.crt
至此CA、服务器、客户端三部分的证书就已经生成了
配置nginx,开启ssl双向认证
nginx用linux的也行,windows的也行,只要linux里面有关键模块【–with-http_ssl_module】和就好了,由于windows下nginx/openresty是自带所有模块的,我就在windows演示了
7443单向、8443双向
双向里面一定注意这个字段ssl_trusted_certificate,没有这个的话也还是会报错,我是一直都加着
server {
listen 7443 ssl;
listen [::]:7443 ssl;
server_name example.com www.example.com;
ssl_certificate E:\\tools\pki\server.crt;
ssl_certificate_key E:\\tools\pki\server.key;
location / {
root html;
index index.html index.htm;
}
}
server {
listen 8443 ssl;
listen [::]:8443 ssl;
server_name example.com www.example.com;
ssl_certificate E:\\tools\pki\server.crt;
ssl_certificate_key E:\\tools\pki\server.key;
ssl_verify_client on;
ssl_trusted_certificate E:\\tools\pki\ca.crt;
ssl_client_certificate E:\\tools\pki\ca.crt;
location / {
root html;
index index.html index.htm;
}
}
使用curl测试ssl双向认证
curl没有使用客户端证书去请求,会报400错误。如果使用的客户端证书不是由特定CA签发的,也同样会报400错误。
用不带证书的,会报400
curl -k -vo /dev/null https://www.example.com/ --resolve www.example.com:443:127.0.0.1
用带证书的
curl -k -vo /dev/null https://www.example.com/ --resolve www.example.com:443:127.0.0.1 --cert ./client.crt --key ./client.key
使用浏览器测试ssl双向认证
启动nginx之后,只要日志里面没有报错,就可以开始愉快的验证了
单向
先看7443的单向,上面也说了单向只是客户端验证服务器,而服务器的证书是我自己颁发的,那显然会弹框,所以这需要我们手动去信任,
会显示是不安全的HTTPS,当然算法、TLS版本我们都可以在配置里指定
双向
双向主要的功能是服务器验证客户端,这类场景适合:
1、有明确的白名单要求
2、IP白名单无法满足,比如IP是变的,或者是一个很大的范围,这样防火墙无法配置,通过服务器验证客户端这个功能可以完美替代IP白名单
采用双向认证后,会生成配对的根证书和客户端证书,根证书刚刚配置在nginx服务器内,客户端证书就发给需要访问这个web的客户了,所以客户端证书如何发,带外等等是需要根据具体业务情况而定的
如果没有客户端证书,是这样的
双击安装我们导出的p12文件
如果刚刚在生成证书的时候没有设置密码,就一路下一步
如果设置密码了,这里必须得输入,不然过不去
最后出现了导入成功
关闭刚刚的浏览器(为了清理缓存,我都启动的是无痕)
查看浏览器里面的客户端证书,可以看到刚刚安装的,注意这种双击安装是全局的,每个浏览器都能看到
再次访问就会提示选择证书,选择后,就能正常访问了
命令汇总
生成自签CA证书
openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt -subj "/C=CN/O=People's Republic of China/CN=China CA"
生成服务器证书
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr -subj "/C=CN/O=People's Republic of China/CN=example.com"
openssl x509 -req -in server.csr -out server.crt -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 -extfile <(sed "/\[ v3_req \]/ a\subjectAltName = @alt_names" /etc/ssl/openssl.cnf <(printf "\n[alt_names]\nDNS.1=example.com\nDNS.2=www.example.com")) -extensions v3_req
生成客户端证书
openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr -subj "/C=CN/O=People's Republic of China/CN=Private certificate assigned to Tom"
openssl x509 -req -in client.csr -out client.crt -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650
curl命令
curl -k -vo /dev/null https://www.example.com/ --resolve www.example.com:443:127.0.0.1
curl -k https://www.example.com/ --resolve www.example.com:443:127.0.0.1
curl -k -vo /dev/null https://www.example.com/ --resolve www.example.com:443:127.0.0.1 --cert ./client.crt --key ./client.key
tomcat
要使用keytool进行证书的签发
如果只是测试的话,不用加servelet,配好server.xml访问就行