menu Chancel's Blog
rss_feed lightbulb_outline

Cent7OS Nginx双向验证配置(自动脚本)

warning 这篇文章距离上次更新于749天前,文中部分信息可能已失效,请自行甄别无效内容。

最近要做一个客户端认证的方案,查找了网上不少证书方案,发现在Cent7下做证书的例子很少,而且大部分资料都只是直接抛命令,而不去解释这一步做了什么,第一次了解证书的人看到key/csr/crt/pem/pfx这么多私钥/证书有点懵,故整理一下关于SSL的知识点

SSL双向认证

双向认证的意思是既要客户端认可服务端(即HTTPS,避免伪造的服务端站点),也要服务端认可客户端,类似于网银等支付场景时可以避免某些恶意的客户端进行访问。 https全称为(Hypertext Transfer Protocol Secure),与HTTP不同的地方在于TCP与HTTP之间存在一个加密/身份验证层,提供了身份验证于加密通讯的方法。采用HTTPS的服务端必须从CA(Certificate Authority)处申请一个证明服务器用途的证书(包含了私钥),客户/浏览器内置了CA厂商的证书(包含公钥),可以简单总结一下流程。

  • 单向认证(https)

    1. 浏览器:发送SSL版本信息
    2. 服务端:接收到随机数以及SSL版本信息,返回自己的SSL版本信息以及证书、随机数等信息
    3. 浏览器:接收到证书、随机数以及服务端的SSL的版本信息,读取证书中的证书所有者、有效期等信息进行一一校验,再在已知的CA机构颁发的证书(内置于浏览器)中寻找相对应的证书信息进行检验,检验证书正确后将自己支持的对称加密方案发送给服务端
    4. 服务端:选择浏览器支持对称加密算法,将选择的加密算法使用公钥进行加密并发送给浏览器
    5. 浏览器:接收到加密方式之后使用私钥进行解密并产生随机码作为对称加密密钥,使用服务端公钥加密并发送给服务端
    6. 服务端:接受到加密密匙之后,使用私钥对加密信息进行解密,获得了对称加密的密钥,使用对称加密加密接下来所有通信信息与浏览器进行通信
  • 双向认证

    1. 浏览器:发送SSL版本信息
    2. 服务端:接收到随机数以及SSL版本信息,返回自己的SSL版本信息以及证书、随机数等信息
    3. 浏览器:接收到证书、随机数以及服务端的SSL的版本信息,读取证书中的证书所有者、有效期等信息进行一一校验,再在已知的CA机构颁发的证书(内置于浏览器)中寻找相对应的证书信息进行检验,检验证书正确后将自己的证书以及公钥发送到服务端,随后再次发送自己支持的对称加密算法列表
    4. 服务端:接收客户端证书,对证书进行检验,检验证书正确后,选择浏览器支持对称加密算法,将选择的加密算法使用公钥进行加密并发送给浏览器
    5. 浏览器:接收到加密方式之后使用私钥进行解密并产生随机码作为对称加密密钥,使用服务端公钥加密并发送给服务端
    6. 服务端:接受到加密密匙之后,使用私钥对加密信息进行解密,获得了对称加密的密钥,使用对称加密加密接下来所有通信信息与浏览器进行通信

服务端如何启用HTTPS

服务端启用HTTPS配置较为简单,一般流程为

  • 向CA证书商家申请证书
  • 下载证书,病更改NGINX配置指向证书
  • 重新读取NGINX配置即可完成HTTPS配置

申请证书的流程网上很多,这里我们可以先手动CA产生一个本地的HTTPS证书(切勿在生产环境下使用这种方法,会提示证书不安全)

  1. 先创建并切换到存放HTTPS证书的文件夹

     mkdir /etc/nginx/ssl_certs
     cd /etc/nginx/ssl_certs
  2. 制作CA私钥和证书,全部配置填"."

     openssl genrsa -out ca.key 2048
     openssl req -new -x509 -days 3650 -key ca.key -out ca.crt
  3. 制作服务器证书签发文件,除了Common Name填入域名,其他全部填入"."以便和CA根证书对应

     openssl genrsa -out server.pem 1024
     openssl rsa -in server.pem -out server.key
     openssl req -new -key server.pem -out server.csr
  4. 使用CA证书进行签发

     openssl x509 -req -sha256 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 -out server.crt
  5. 编辑nginx配置并让nginx重新读取配置

     vim /etc/nginx/conf.d/default.conf
    
     server {
         listen       443 ssl;
         server_name  www.example.com;
    
         #charset koi8-r;
         #access_log  /var/log/nginx/host.access.log  main;
         ssl on;
         ssl_certificate /etc/nginx/ssl/server.crt;      # 服务端HTTPS的证书,不能自己产生,否则会提示证书不安全,该配置与客户端证书无关
         ssl_certificate_key /etc/nginx/ssl/server.key;  # 服务端HTTPS的证书,不能自己产生,否则会提示证书不安全,该配置与客户端证书无关
         location / {
             proxy_pass_header Server;
             proxy_pass_header X-Scheme;
             proxy_set_header Host $http_host;
             proxy_set_header X-SSL-CERT $ssl_client_escaped_cert;
             proxy_set_header X-SSL-CERT-DN $ssl_client_s_dn;
             proxy_set_header X-SSL-CERT-VERIFY $ssl_client_verify;
             proxy_set_header X-Real-IP $remote_addr;
             proxy_pass http://192.168.10.100:5000/;
         }
     }
    
     nginx -s reload
  6. 测试是否可以使用HTTPS访问(修改HOSTS文件将www.example.com指向配置好的服务器即可)

     # 因为证书是我们自己签发的,所以必须使用insecure忽略安全提示否则curl会返回证书不安全测试失败的结果
     curl --insecure 'https://www.example.com' -v

客户端如何启用证书验证

客户端证书一般就采用自己配置根证书来签发自己的客户端证书,签发客户端证书会包含几个重要的属性,分别是

  • 地区信息(国家、省份、城市)
  • 公司信息(公司名称、该证书拥有者的部门信息)
  • Common Name信息(也叫CN信息,一般会把一些重要信息存储在这里,比如证书的有效信息/绑定信息等)
  • 邮箱信息
  • 证书有效期、证书导入/导出密码

制作客户端证书的流程一般为

  1. 制作自己的CA私钥(ca.key)
  2. 使用CA私钥制造CA根证书(cacert.crt)
  3. 制作客户端私钥,并合成待签发csr文件(client.key,client.csr)
  4. 使用CA证书对客户端待签发文件进行签发产生客户端的crt证书(client.crt)
  5. 转换客户端证书为适合浏览器的证书格式(client.pfx,client.p12)

我们来制作第一张客户端证书

首先要编辑默认CA创建规则,根据需要自行修改一下默认的参数

vim /etc/pki/tls/openssl.cnf

/etc/pki/CA/            # 所有资料全存放在此目录下
/etc/pki/CA/certs/      # 存放CA证书
/etc/pki/CA/crl/        # 存放证书吊销列表
/etc/pki/CA/index.txt   # 存放可用、不可用证书的数据库
/etc/pki/CA/newcerts    # 存放CA的新目录
/etc/pki/CA/cacert.pem  # 生成的自签名证书
/etc/pki/CA/serial      # 下个证书的编号,16进制,多从00或01开始
/etc/pki/CA/crlnum      # 下一个吊销证书的编号
/etc/pki/CA/crl.pem     # 下一个吊销列表
/etc/pki/CA/private/cakey.pem  # 默认密钥

# 匹配策略的可选值
match                   # 必须匹配,默认是国家、州(省)、组织名称
supplied                # 必填,为哪个主机申请证书,一般对应域名
optional                # 可选

根据具体的环境调整好上述的参数之后,我们就可以开始制作客户端证书(下面的目录要根据你上面调整的参数做变化),接下来开始制作流程

  1. 生成创建证书所必须的基本文件

     touch /etc/pki/CA/index.txt                                # 生成数据库文件,记录证书信息(包含序列号、序号、证书自定义CN信息等)
     echo 00 > /etc/pki/CA/serial                               # 生成存放证书编号的文件(一般存储即将颁发的下一个证书序号)
  2. 生成签证客户端的根证书

     cd /etc/pki/CA                                             
     (umask 066;openssl genrsa -out private/cakey.pem 1024 )
     openssl  req -new -x509  -key private/cakey.pem  -days 3650 -out cacert.pem  # 这里签发10年有效期
  3. 签发客户端的证书(此处有提供一键脚本执行)

     mkdir /etc/nginx/client_ssl                                     # 创建存放客户端证书的文件夹
     cd /etc/nginx/client_ssl                                        # 切换到存放客户端证书的目录
     (umask 066; openssl genrsa -out client_01.key 1024)             # 创建客户端证书私钥
     openssl  req -new -key client_01.key  -out client_01.csr        # 创建请求根证书签证的文件
     openssl  ca -in client_01.csr  -out client_01.crt -days 730     # 创建客户端证书
  4. Nginx配置参考

     server {
         listen       443 ssl;
         server_name  www.example.com;
    
         #charset koi8-r;
         #access_log  /var/log/nginx/host.access.log  main;
         ssl on;
         ssl_certificate /etc/nginx/ssl/server.crt;      # 服务端HTTPS的证书,不能自己产生,否则会提示证书不安全,该配置与客户端证书无关
         ssl_certificate_key /etc/nginx/ssl/server.key;  # 服务端HTTPS的证书,不能自己产生,否则会提示证书不安全,该配置与客户端证书无关
         ssl_client_certificate /etc/nginx/ssl/ca.crt;   # 客户端的CA根证书,由自己的机器OPENSSL生成
         ssl_verify_client optional;                     # 是否启用客户端验证,ON为启用,OFF为不启用,如需自定义验证结果处理则填入optional
         if ($ssl_client_verify = NONE) {
             return 303 http://www.example.com/error;
         }
             location / {
                 proxy_pass_header Server;
                 proxy_pass_header X-Scheme;
                 proxy_set_header Host $http_host;
                 proxy_set_header X-SSL-CERT $ssl_client_escaped_cert;   # 转发证书信息
                 proxy_set_header X-SSL-CERT-DN $ssl_client_s_dn;        # 转发证书的CN信息
                 proxy_set_header X-SSL-CERT-VERIFY $ssl_client_verify;  # 转发证书的验证结果,成功为success
                 proxy_set_header X-Real-IP $remote_addr;
                 proxy_pass http://192.168.10.100:5000/;
    
         }
     }
  5. 测试客户端证书能否正常访问网页

     # -v参数可以打印详细信息以便我们核查证书的详细信息
     curl --insecure --key ./client.key --cert ./client.crt 'https://www.example.com' -v

注:一键生成客户端证书脚本

```
#!/bin/bash -e

# 运行脚本前请记得设置好openssl.cnf配置文件
# 运行成功返回0,运行失败(缺少参数)返回-1

show_help() {
    echo "$0 [-h|-?|--help] [--ou ou] [--cn cn] [--email email]"
    echo "-h|-?|--help    显示帮助"
    echo "--ou            设置组织或部门名"
    echo "--cn            设置证书的DN信息"
    echo "--email         设置证书的邮箱信息"
    echo "--days          设置证书的有效时间"
    echo "--out           设置证书的输出目录(含文件名)"
}

while [[ $# -gt 0 ]]; do
    case $1 in
    -h | -\? | --help)
        show_help
        exit 0
        ;;
    --ou)
        OU="${2}"
        shift
        ;;
    --cn)
        CN="${2}"
        shift
        ;;
    --email)
        emailAddress="${2}"
        shift
        ;;
    --days)
        days="${2}"
        shift
        ;;
    --out)
        out="${2}"
        shift
        ;;
    --)
        shift
        break
        ;;
    *)
        echo -e "Error: $0 invalid option '$1'\nTry '$0 --help' for more information.\n" >&2
        exit -1
        ;;
    esac
    shift
done

# 创建客户端证书
# 非交互式方式创建以下内容:
# 国家名(2个字母的代号)
C=CN
# 省
ST=GuangDong
# 市
L=GuangDong
# 公司名
O=TY
# 部门名
OU=${OU:-未知}
# DN信息
CN=${CN:-未知}
# 邮箱地址
emailAddress=${emailAddress:-virtual@example.com}

# 创建私钥
openssl req -utf8 -nodes -newkey rsa:2048 -keyout "${out}.key" -new -days "${days}" -out "${out}.csr" -subj "/C=${C}/ST=${ST}/L=${L}/O=${O}/OU=${OU}/CN=${CN}/emailAddress=${emailAddress}"
# 使用根证书进行进行签证
openssl ca -utf8 -batch -days 36500 -in "${out}.csr" -out "${out}.crt"
# 转换客户端证书的类型为浏览器支持的模式
openssl pkcs12 -export -inkey "${out}.key" -in "${out}.crt" -passout pass: -out "${out}.pfx"

exit 0
```

其他常用命令

SSL证书常用格式转换

# crt转pfx(p12)
openssl pkcs12 -export -inkey server.key -in server.crt -out server.pfx

# csr转pfx(p12)
openssl pkcs12 -export -inkey server.key -in server.csr -out server.pfx

# pfx转jks
keytool -importkeystore -v  -srckeystore client.pfx -srcstoretype pkcs12  -destkeystore client.keystore -deststoretype jks 

# jks转p12(pfx)
keytool -importkeystore -srckeystore client_pri.keystore -destkeystore client_pri.p12 -srcstoretype JKS -deststoretype PKCS12 -srcalias imgo.tv -destalias imgo.tv -noprompt

# pfx转x509
openssl pkcs12 -in onovps.com.pfx -nodes -out onovps.com.pem 
openssl rsa -in onovps.com.pem -out onovps.com.key
openssl x509 -in onovps.com.pem -out onovps.com.crt

资料参考

使用OpenSSL构建私有CA - linux Nginx SSL快速双向认证配置(脚本) - Dteam SSL证书常用格式转换 - Linvo 带你使用Nginx实现HTTPS双向验证 - qw87112 创建CA、申请证书、吊销证书 - a_pan NGINX 配置 SSL 双向认证 - godjob

阅读: 180
分类: 编程语言
创建时间: 2019-07-18 19:05:16
更新时间: 2019-07-18 19:05:16
博文目录

[[replyMessage== null?"发表评论":"@" + replyMessage.m_author]]

account_circle
email
web_asset
textsms

评论列表([[messageList.data.items.length]])

[[messageItem.m_author]] [[messageItem.m_author]]
[[messageItem.create_time]]
[[messageItem.m_environ.browser]] [[messageItem.m_environ.os]] [[messageItem.m_environ.device]]
[[subMessage.m_author]] [[subMessage.m_author]] @ [[subMessage.parent_message.m_author]] [[subMessage.parent_message.m_author]]
[[subMessage.create_time]]
[[subMessage.m_environ.browser]] [[subMessage.m_environ.os]] [[subMessage.m_environ.device]]