nginx 自签证书实现配置 https 双向认证

什么是双向认证?

双向认证,顾名思义,客户端和服务器端都需要验证对方的身份,在建立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;
	
}

导入证书后访问页面,会出现多证书选择了,这时选择你要的证书打开页面就可以了。

日志信息

This entry was posted in 服务器. Bookmark the permalink.