技术背景


  HTTP双向认证过程中,每个用户都需要有自己惟一的证书,通过CA的级联证书模式,使所有的证书都对应同一个根证书。这样需要自己生成一套CA根级证书,再借助其生成二级证书作为client证书。此时client私钥签名不仅可以通过对应的client公钥验证,还可通过根证书的公钥进行验证。

 

单向验证与双向验证的区别


  单向验证: 指客户端验证服务器端证书,服务器并不需要验证客户端证书。

  双向验证:指客户端验证服务器端证书,而服务器也需要通过CA的公钥证书来验证客户端证书。

 

详细的握手过程


单向验证

1、浏览器发送一个连接请求给安全服务器。

2、服务器将自己的证书,以及同证书相关的信息发送给客户浏览器。

3、客户浏览器检查服务器送过来的证书是否是由自己信赖的CA中心所签发的。如果是,就继续执行协议;如果不是,客户浏览器就给客户一个警告消息:警告客户这个证书不是可以信赖的询问客户是否需要继续。

4、接着客户浏览器比较证书里的消息,例如域名和公钥,与服务器刚刚发送的相关消息是否一致,如果是一致的,客户浏览器认可这个服务器的合法身份。

5、浏览器随机产生一个用于后面通讯的“通话密钥”,然后用服务器的公钥对其加密,然后将加密后的“预主密码”传给服务器。

6、服务器从客户发送过来的密码方案中,选择一种加密程度最高的密码方案,用服务器的私钥加密后通知浏览器。

7、浏览器针对这个密码方案,接着用服务器的公钥加过密后发送给服务器。

8、服务器接收到浏览器送过来的消息,用自己的私钥解密,获得。

9、服务器、浏览器接下来的通讯都是用对称密码方案,使用相同的对称密钥。

 双向验证

1、浏览器发送一个连接请求给安全服务器。

2、服务器将自己的证书,以及同证书相关的信息发送给客户浏览器。

3、客户浏览器检查服务器送过来的证书是否是由自己信赖的CA中心所签发的。如果是,就继续执行协议;如果不是,客户浏览器就给客户一个警告消息:警告客户这个证书不是可以信赖的询问客户是否需要继续。

4、接着客户浏览器比较证书里的消息,例如域名和公钥,与服务器刚刚发送的相关消息是否一致,如果是一致的,客户浏览器认可这个服务器的合法身份。

5、服务器要求客户的身份认证,用户可以建立一个随机数然后对其进行数字签名,将这个含有签名的随机数和客户自己的证书以及加密过的“预主密码”一起传给服务器。

6、服务器必须检验客户证书和签名随机数的合法性,具体的合法性验证过程包括:客户的证书使用日期是否有效,为客户提供证书的CA 是否可靠,发行CA 的公钥能否正确解开客户证书的发行CA的数字签名,检查客户的证书是否在证书废止列表(CRL)中。检验如果没有通过,通讯立刻中断;如果验证通过,服务器将用自己的私钥解开加密的“预主密码”,然后执行一系列步骤来产生主通讯密码(客户端也将通过同样的方法产生相同的主通讯密码)。

7、客户浏览器告诉服务器自己所能够支持的通讯对称密码方案。

8、服务器从客户发送过来的密码方案中,选择一种加密程度最高的密码方案,用客户的公钥加过密后通知浏览器。

9、浏览器针对这个密码方案,选择一个通话密钥,接着用服务器的公钥加过密后发送给服务器。

10、服务器接收到浏览器送过来的消息,用自己的私钥解密,获得通话密钥。

11、服务器、浏览器接下来的通讯都是用对称密码方案,使用相同的对称密钥。

 

安装前准备


 1、准备安装包

  获取PCRE(Perl Compatible Regular Expressions是一个Perl库,包括 perl 兼容的正则表达式库)、 OPENSSL(是一个安全套接字层密码库,囊括主要的密码算法、常用的密钥和证书封装管理功能及SSL协议,并提供丰富的应用程序供测试或其它目的使用)、 ZLIB(提供数据压缩用的函式库)的安装包。在本例中版本分别为pcre-8.36、openssl-1.0.2a、 zlib-1.2.8、 nginx-1.9.0。在安装NGINX软件之前需要依次安装以上软件,如果操作系统中包括上述软件,则不需要安装。

2、安装PCER



unzip "$CURRENT_PATH/$PCRE.zip" -d "$CURRENT_PATH"
cd "$CURRENT_PATH/$PCRE"
./configure
make
make install



 3、安装OPENSSL



tar -xvf "$CURRENT_PATH/$OPENSSL.tar.gz" -C "$CURRENT_PATH"
cd "$CURRENT_PATH/$OPENSSL"
./config shared --prefix=/usr/local --openssldir=/usr/local/ssl
make
make install



   注:OPENSSL的安装目录为/usr/local,OPENSSL的配制文件为/usr/local/ssl/目录下openssl.cnf。后续在CA部分需要使用到。

4、安装ZLIB



tar -xvf "$CURRENT_PATH/$ZLIB.tar.gz" -C "$CURRENT_PATH"
cd "$CURRENT_PATH/$ZLIB"
./configure
make
make install



 5、安装nginx(以上软件安装成功以后)



tar -xvf "$CURRENT_PATH/$NGINX.tar.gz" -C "$CURRENT_PATH"
cd "$CURRENT_PATH/$NGINX"
./configure --prefix=$NGINX_PATH --with-http_ssl_module
make
make install



  注:在NGINX安装中,必须要加上--with-http_ssl_module,否则无法配制HTTPS认证。

 

OPENSSL目录配置准备


1、配制OPENSSL需要的目录和文件



mkdir /etc/pki/ca_inorsight
cd /etc/pki/ca_inorsight
mkdir root server client newcerts
echo 01 > serial
echo 01 > crlnumber
touch index.txt



 2、修改openssl配置



vi  /usr/local/ssl/openssl.cnf



  修改里面的如下参数:



dir = /etc/pki/ca_inorsight
certificate = $dir/root/ca.crt
private_key = $dir/root/ca.key



 

创建CA根级证书


1、生成key:



openssl genrsa -out /etc/pki/ca_inorsight/root/ca.key



 2、生成csr:



openssl req -new -key /etc/pki/ca_inorsight/root/ca.key -out /etc/pki/ca_inorsight/root/ca.csr



 3、生成crt:



openssl x509 -req -days 3650 -in /etc/pki/ca_inorsight/root/ca.csr -signkey /etc/pki/ca_inorsight/root/ca.key -out /etc/pki/ca_inorsight/root/ca.crt



 4、生成crl:



openssl ca -gencrl -out /etc/pki/ca_inorsight/root/ca.crl -crldays 7



  生成的根级证书文件都在/etc/pki/ca_inorsight/root/目录下。

  注:创建证书时,证书密码设置长度>=6位,因为java的keytool工具貌似对它有要求。

 

创建SERVER证书


1、生成key:



openssl genrsa -out /etc/pki/ca_inorsight/server/server.key



 2、生成csr:



openssl req -new -key /etc/pki/ca_inorsight/server/server.key -out /etc/pki/ca_inorsight/server/server.csr



3、生成crt:



openssl ca -in /etc/pki/ca_inorsight/server/server.csr -cert /etc/pki/ca_inorsight/root/ca.crt -keyfile /etc/pki/ca_inorsight/root/ca.key -out /etc/pki/ca_inorsight/server/server.crt -days 3650



 说明:  

 1、这里生成的crt是刚才ca根级证书下的级联证书,其实server证书主要用于配置正常单向的https,所以不使用级联模式也可以:



openssl rsa -in /etc/pki/ca_inorsight/server/server.key -out /etc/pki/ca_inorsight/server/server.key
openssl x509 -req -in /etc/pki/ca_inorsight/server/server.csr -signkey /etc/pki/ca_inorsight/server/server.key -out /etc/pki/ca_inorsight/server/server.crt -days 3650



 2、-days 参数可根据需要设置证书的有效期,例如默认365天。

 

创建CLIENT证书


 1、生成key:



openssl genrsa -des3 -out /etc/pki/ca_inorsight/client/client.key 1024



 2、生成csr:



openssl req -new -key /etc/pki/ca_inorsight/client/client.key -out /etc/pki/ca_inorsight/client/client.csr



3、生成crt:



openssl ca -in /etc/pki/ca_inorsight/client/client.csr -cert /etc/pki/ca_inorsight/root/ca.crt -keyfile /etc/pki/ca_inorsight/root/ca.key -out /etc/pki/ca_inorsight/client/client.crt -days 3650



说明:
1、这里就必须使用级联证书,并且可以重复该步骤,创建多套client证书。

2、生成crt时可能会遇到如下报错:

  openssl TXT_DB error number 2 failed to update database

  可参照这里进行操作,即将index.txt.attr中unique_subject = no,在实际应用场景中,证书subject应该有所不同。生产环境上不建议修改此值。

 

配置NGINX


1、在nginx.conf配置,在此指列出需要配置的server段部分代码:



ssl_certificate  /etc/pki/ca_inorsight/server/server.crt;#server公钥
ssl_certificate_key  /etc/pki/ca_inorsight/server/server.key;#server私钥
ssl_client_certificate   /etc/pki/ca_inorsight/root/ca.crt;#根级证书公钥,用于验证各个二级client
ssl_verify_client on;



 2、重启nginx生效。

 

nginx.conf代码片段


upstream connrub {
        sticky name=route;        
        server 172.31.122.187:8081;   #后端应用的IP,支持http和https端口,可配置多个
        server 172.31.124.142:8082;   #后端应用的IP,端口
        check interval=3000 rise=2 fall=5 timeout=1000 type=http;
        check_http_send "GET / HTTP/1.0\r\n\r\n";   #返回节点状态的API,200为OK "GET or HEAD" "/ API路径" "1.0 HTTP协议"
        check_http_expect_alive http_2xx http_3xx http_4xx;
    }
#http配置
    server {
        listen 8080;  #http访问端口
        server_name localhost;
        
       location / {
           proxy_pass http://connrub;
       }
        
        location /nstatus {
            check_status;
            access_log off;
            allow 122.168.21.131;  #允许进行后端服务器状态检查的ip
            allow all; #允许任意ip检查后端服务器状态。不建议配置
            deny all;
        }
    }

#https配置可选
#https配置        
    server {
        listen 8081 ssl;    #8081为https端口
        server_name localhost; #localhost修改为节点IP
        ssl_certificate     ./ssl/nginx.pem; 
        ssl_certificate_key ./ssl/nginx.key; 
        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2; 
        ssl_ciphers         HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;         
        ssl_client_certificate ./ssl/rootca.der; #双向认证时开启      
        ssl_verify_client on;    #双向认证时开启
        ssl_verify_depth 2;      #双向认证时开启
         location / {
           proxy_pass https://connrub; #后端应用开启https,如果后端服务器没有开启https,则为http://connrub
         }
         location /nstatus {
            check_status;
             access_log off;
             #allow 192.168.2.11; #允许进行后端服务器状态检查的ip
             #allow all; #允许任意ip检查后端服务器状态。不建议配置
             deny all;
        }
    }



 

 

      完毕。