什么是双向认证?
双向认证,顾名思义,客户端和服务器端都需要验证对方的身份,在建立HTTPS连接的过程中,握手的流程比单向认证多了几步。单向认证的过程,客户端从服务器端下载服务器端公钥证书进行验证,然后建立安全通信通道。双向通信流程,客户端除了需要从服务器端下载服务器的公钥证书进行验证外,还需要把客户端的公钥证书上传到服务器端给服务器端进行验证,等双方都认证通过了,才开始建立安全通信通道进行数据传输。
1、单向认证流程
1)客户端发起建立HTTPS连接请求,将SSL协议版本的信息发送给服务器端;
2)服务器端将本机的公钥证书(server.crt)发送给客户端;
3)客户端读取公钥证书(server.crt),取出了服务端公钥;
4)客户端生成一个随机数(密钥R),用刚才得到的服务器公钥去加密这个随机数形成密文,发送给服务端;
5)服务端用自己的私钥(server.key)去解密这个密文,得到了密钥R
6)服务端和客户端在后续通讯过程中就使用这个密钥R进行通信了。
2、双向认证流程
1)客户端发起建立HTTPS连接请求,将SSL协议版本的信息发送给服务端;
2)服务器端将本机的公钥证书(server.crt)发送给客户端;
3)客户端读取公钥证书(server.crt),取出了服务端公钥;
4)客户端将客户端公钥证书(client.crt)发送给服务器端;
5)服务器端使用根证书(root.crt)解密客户端公钥证书,拿到客户端公钥;
6)客户端发送自己支持的加密方案给服务器端;
7)服务器端根据自己和客户端的能力,选择一个双方都能接受的加密方案,使用客户端的公钥加密后发送给客户端;
8)客户端使用自己的私钥解密加密方案,生成一个随机数R,使用服务器公钥加密后传给服务器端;
9)服务端用自己的私钥去解密这个密文,得到了密钥R
10)服务端和客户端在后续通讯过程中就使用这个密钥R进行通信了。
3、证书准备
整个双向认证的流程需要六个证书文件:
1) 根证书:root.crt
2) 服务器端公钥证书:server.crt
3) 服务器端私钥文件:server.key
4) 客户端公钥证书:client.crt
5) 客户端私钥文件:client.key
6) 客户端集成证书(包括公钥和私钥,用于浏览器访问场景):client.p12
互联网使用一般向证书机构去申请签发,这是需要收费的。我们内部使用的话,可以自签证书。
4、自签证书
生成这一些列证书之前,我们需要先生成一个CA根证书,然后由这个CA根证书颁发服务器公钥证书和客户端公钥证书。
在创建证书请求文件的时候需要注意,同样下面生成服务器请求文件和客户端请求文件均要注意:
**** ***********************************************************
根证书的 Common Name 可以填写root 或者个人、单位信息
服务器端证书的 Common Name 可以填写域名或者IP或者单位
客户端证书的 Common Name 可以填写个人信息
****************************************************************
一定要注意的是,根证书的 Common Name 字段和客户端证书、服务器端证书不能一样。其他所有字段的填写,根证书、服务器端证书、客户端证书需保持一致就可以了。
我使用 openssl 在centos/mac 环境下生成的证书,windows环境安装 openssl 请自行百度。
4.1 自签根证书
#创建根证书私钥
openssl genrsa -out root.key 2048
#创建根证书请求文件
openssl req -new -out root.csr -key root.key
#创建根证书
openssl x509 -req -in root.csr -out root.crt -signkey root.key -days 3650
生成根证书请求文件 时需要注意 Common Name 可以填写root 或者个人、单位信息 。其他字段与根证书一致。
创建证书请求文件参考:
Country Name (2 letter code) [XX]:cn
State or Province Name (full name) []:gd
Locality Name (eg, city) [Default City]:gz
Organization Name (eg, company) [Default Company Ltd]:kunyuan
Organizational Unit Name (eg, section) []:kunyuan
Common Name (eg, your name or your server's hostname) []:root
Email Address []:lin@kunyuan.tech
经过上面三个命令行,我们最终可以得到一个签名有效期为10年的根证书root.crt,后面我们可以用这个根证书去颁发服务器证书和客户端证书。
4.2 自签服务器端证书
#生成服务器端证书私钥
openssl genrsa -out server.key 2048
#生成服务器证书请求文件
openssl req -new -out server.csr -key server.key
#生成服务器端公钥证书
openssl x509 -req -in server.csr -out server.crt -signkey server.key -CA root.crt -CAkey root.key -CAcreateserial -days 3650
生成服务器证书请求文件 时需要注意 Common Name 要填写域名或者服务器IP地址。其他字段与根证书一致。
创建证书请求文件参考:
Country Name (2 letter code) [XX]:cn
State or Province Name (full name) []:gd
Locality Name (eg, city) [Default City]:gz
Organization Name (eg, company) [Default Company Ltd]:kunyuan
Organizational Unit Name (eg, section) []:kunyuan
Common Name (eg, your name or your server's hostname) []:127.0.0.1
Email Address []:lin@kunyuan.tech
经过上面的三个命令,我们得到:
server.key:服务器端的密钥文件
server.crt:有效期十年的服务器端公钥证书,使用根证书和服务器端私钥文件一起生成。
4.3 自签客户端证书
#生成客户端证书密钥
openssl genrsa -out client.key 2048
#生成客户端证书请求文件
openssl req -new -out client.csr -key client.key
#生客户端证书
openssl x509 -req -in client.csr -out client.crt -signkey client.key -CA root.crt -CAkey root.key -CAcreateserial -days 3650
#生客户端p12格式证书,记住设置的密码,给客户端电脑安装时需要使用
openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12
使用根证书和客户端私钥一起生成 client.p12,这个证书文件包含客户端的公钥和私钥,主要用来给浏览器访问使用。
生成客户端证书请求文件 时需要注意 Common Name 可以填写个人信息。其他字段与根证书一致。
创建证书请求文件参考:
Country Name (2 letter code) [XX]:cn
State or Province Name (full name) []:gd
Locality Name (eg, city) [Default City]:gz
Organization Name (eg, company) [Default Company Ltd]:kunyuan
Organizational Unit Name (eg, section) []:kunyuan
Common Name (eg, your name or your server's hostname) []:127.0.0.1
Email Address []:lin@kunyuan.tech
所有证书创建完成后,最后会使用到 server.crt、server.key、root.crt (这3个为服务器使用)和 client.p12 (客户端使用)
5、配置nginx
nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server_tokens off;
# 开启gzip
gzip on;
# 低于1kb的资源不压缩
gzip_min_length 1k;
# 设置压缩所需要的缓冲区大小
gzip_buffers 4 16k;
# 压缩级别【1-9】,越大压缩率越高,同时消耗cpu资源也越多,建议设置在4左右。
gzip_comp_level 4;
# 需要压缩哪些响应类型的资源,缺少的类型自己补。
gzip_types text/css text/javascript application/javascript;
# 配置禁用gzip条件,支持正则。此处表示ie6及以下不启用gzip(因为ie低版本不支持)
gzip_disable "MSIE [1-6]\.";
# 是否添加“Vary: Accept-Encoding”响应头,
gzip_vary on;
# 设置gzip压缩针对的HTTP协议版本,没做负载的可以不用
# gzip_http_version 1.0;
include /etc/nginx/conf.d/*.conf;
}
conf.d/v-host.conf
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /etc/nginx/certs/server.crt;#配置证书位置
ssl_certificate_key /etc/nginx/certs/server.key;#配置秘钥位置
ssl_client_certificate /etc/nginx/certs/root.crt;#双向认证根证书
ssl_verify_client on; #双向认证,单向认证将这个值设置为 off
location / {
proxy_pass http://127.0.0.1:5601;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
修改配置后需要重启nginx
6、配置浏览器证书
在服务器配置好证书好,访问你的地址进行验证。在没有安装证书前,会提示400错误。
配置证书,以chrome为例。
#浏览器输入
chrome://settings/
点击管理证书,然后导入
按照导入步骤,注意证书存储为“个人”
完成证书导入。重启浏览器,再打开页面进行验证,此时会提示你确认证书即可访问。
7、自我增值:多证书配置
有些业务场景需要每个人一个证书,我们就可以实现多证书配置。多证书需要结合后端进行访问控制。
7.1 证书生成
接4、证书生成步骤,继续生成多个人的证书。
重复此证书生成步骤,生成多个证书
#生成客户端个人证书请求文件,如linky/linky2/linky3的,对应生成的文件需要改名
openssl req -new -out linky.csr -key client.key
#生客户端证书
openssl x509 -req -in linky.csr -out linky.crt -signkey client.key -CAkey root.key -CAcreateserial -days 30
#生客户端p12格式证书,记住设置的密码,给客户端电脑安装时需要使用
openssl pkcs12 -export -in linky.crt -inkey client.key -out linky.p12
请求文件配置参考:
#配置1-linky
Country Name (2 letter code) [XX]:cn
State or Province Name (full name) []:gd
Locality Name (eg, city) [Default City]:gz
Organization Name (eg, company) [Default Company Ltd]:kunyuan
Organizational Unit Name (eg, section) []:kunyuan
Common Name (eg, your name or your server's hostname) []:linky
Email Address []:linky@kunyuan.tech
#配置2-linky2
Country Name (2 letter code) [XX]:cn
State or Province Name (full name) []:gd
Locality Name (eg, city) [Default City]:gz
Organization Name (eg, company) [Default Company Ltd]:kunyuan
Organizational Unit Name (eg, section) []:kunyuan
Common Name (eg, your name or your server's hostname) []:linky2
Email Address []:linky2@kunyuan.tech
#配置3-linky3
Country Name (2 letter code) [XX]:cn
State or Province Name (full name) []:gd
Locality Name (eg, city) [Default City]:gz
Organization Name (eg, company) [Default Company Ltd]:kunyuan
Organizational Unit Name (eg, section) []:kunyuan
Common Name (eg, your name or your server's hostname) []:linky3
Email Address []:linky3@kunyuan.tech
生成客户端证书请求文件 时需要注意 Common Name 可以填写个人信息。其他字段与根证书一致。
至此,我们得到3个人的p12文件,分别是 linky.p12、linky2.p12、linky3.p12,对应发送给相对的人使用即可。
7.2 nginx 配置
同时,需要在nginx配置中做些调整
conf.d/v-host.conf
# 负载配置
upstream webServer {
server 127.0.0.1:5601; #服务器1
server 127.0.0.2:5601; #服务器2
}
# http 跳转 https
server {
listen 80;
server_name localhost;
error_page 497 https://$host:$server_port$uri$is_args$args;
}
# 日志输出,加上 ssl 相关信息,用于调试,生产环境可删除
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" - $ssl_client_s_dn';
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /etc/nginx/certs/server.crt;#配置证书位置
ssl_certificate_key /etc/nginx/certs/server.key;#配置秘钥位置
ssl_client_certificate /etc/nginx/certs/root.crt;#双向认证根证书
ssl_verify_client on; #双向认证,单向认证将这个值设置为 off
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log error;
location / {
proxy_pass http://webServer;
proxy_set_header X-Client-Subject-DN $ssl_client_s_dn; # 转发san等信息给后端服务,后端接收此信息做访问权限控制等
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# http 跳转 https
error_page 497 https://$host:$server_port$uri$is_args$args;
}
导入证书后访问页面,会出现多证书选择了,这时选择你要的证书打开页面就可以了。
日志信息