OpenSSL二三事-开启HTTPS双向验证

@xuing  July 7, 2021
本文首发于微信公众号安天垂直响应服务平台,转载需授权。

OpenSSL二三事-开启HTTPS双向验证

缩写地狱

在进行实践之前,我们不妨梳理一下OpenSSL相关的术语、名词、概念。不是很理解也没有关系,接下来的实验,我们会用到一些。应该会有助于理解。

CA(Certificate Authority): 证书颁发机构,听起来相当高大上,但其实也可以是你自己。(所谓自签)

CSR(Certificate Signing Request): 证书签署请求

key(Private Key): 私钥文件,用来签署和生成证书。

CRT(Certificate): 证书文件

PEM(Privacy Enhanced Mail): 非常常见,它是一种可包含多种内容的编码格式(可能有私钥,也可能没有、甚至里面可能还包含根证书、CSR等)。

原本是用于隐私增强邮件的文件格式,现广泛应用于各个场景。

好处在于其使用了BASE64编码后,内容全部都是可见字符。

刚刚说的CRT、KEY、CSR等文件默认都是使用PEM格式进行编码的。如果你看到一个后缀名为PEM,那么他可能包含多种内容。

.pkcs12 .pfx .p12(Public-Key Cryptography Standards 12):

公钥密码学标准 12,对应名称为个人消息交换标准(Personal Information Exchange Syntax Standard)。

是一种有密码加密的文件格式,包含公钥及其对应私钥。

Self Signed Certificate:自签证书:将自己视为证书颁发机构(CA)并生成.crt文件。

还有很多,der,.p7b等等后缀和格式。我们有时间再聊,就本次实验,上述前置知识基本足够了。

什么是双向验证

想必大家都已经相当熟悉HTTPS了,就是地址栏旁边的小锁。

一能保证你和服务器的交流足够安全,不会被中间人监听、篡改。

二能确认你访问的网站的真实性,而不是某个钓鱼网站。

在单向验证中,客户端需要从服务器端下载服务器的公钥证书进行验证。双向验证还需要把客户端的公钥证书上传到服务器端给服务器端进行验证。

双向认证流程

比如我们希望将某个管理后台暴露在公网上,但无论是更换端口,还是修改默认后台路径,都有被黑客爆破出来的风险。

亦或者是后台存在漏洞,未能及时修复或是尚未被公开过的漏洞,若被利用会造成很严重的后果。

此时就可以对此项服务开启双向验证,只有认可的客户端证书才能够正常访问。相当于是加了一层登录验证。毕竟密码登录也是会有弱口令问题的。

开启双向验证

生成证书颁发机构相关文件

1.首先生成CA用的私钥,这是接下来所有证书生成的基础。

openssl genrsa -des3 -out ca.key 4096
  • genrsa: 生成RSA私钥
  • -des3: 采用des3加密
  • -out: 输出的文件名
  • 4096: 私钥大小

生成时,需要提供key的密码。我们这里就使用弱密码root了。

2.下一步生成CA的证书

openssl req -new -x509 -days 3650 -key ca.key -out ca.crt
  • req: 创建证书请求
  • -new: 请求生成新的证书
  • -x509: 输出自签证书而不是证书签署请求
  • -days 3650: 证书的过期时间 (此处为10年)
  • -key: 指定用于证书生成的key
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:CertAuth
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:

输入上一步设置的密码,它将要求您提供有关自签名证书的更多信息。大部分参数均可留空或使用默认值([]中的值)。

例如这里我们修改Organization NameAntiy VS

如果需要PEM格式文件,则只需要把key和crt文件串在一起就好了。

cat ca.key > ca.pem
cat ca.crt >> ca.pem

PEM内容会类似这样:

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,0E2D38C130456B75

3+0Em2EKRkmCCu79bR7E2uFy/G1huIGEGsItwDf0C70Hf2bmUUDYazK/CPZxZCut
PDximngoGaLSdLQ2HWGjjCe59pJxxZknxHu9QVy3mIWLixAZWevDUnoK1q+Wqy0M
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIFSzCCAzOgAwIBAgIUeawaQJUIAPKOKhrIJDjMVCYVx4MwDQYJKoZIhvcNAQEL
BQAwNTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAoM
-----END CERTIFICATE-----

生成客户端证书

1.现在,我们来生成客户端(用户)证书,生成用户私钥的命令与生成CA私钥并无区别。

openssl genrsa -des3 -out user.key 4096

同CA的私钥,我们需要设定一个密码。

2.客户端私钥就不应该被自签了,我们需要生成CSR(证书签署请求),然后由CA进行签署。

openssl req -new -key user.key -out user.csr

命令要求输入证书申请信息。

这里要注意Organization Name字段应该是用户自己,且不同于CA证书的。如:User

3.下一步,我们就可以根据CSR请求通过自签的CA进行下发客户端(用户)证书了。

openssl x509 -req -days 3650 -in user.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out user.crt
  • x509: 公钥证书的标准格式
  • -CA: 指定CA证书
  • -CAkey: 指定CA的Key
  • -set_serial 01: 证书的序列版本。证书过期后,可以通过增加序列号来重新生成。

4.为了能方便的导入Web浏览器,我们还需要生成PFX格式的证书(与Cer证书区别在于除公钥信息还包含私钥信息)

openssl pkcs12 -export -out user.pfx -inkey user.key -in user.crt -certfile ca.crt

命令要求输入user.key的密码,并设置导出密码。

5.生成成功后,我们可以如下命令,用CA证书尝试验证解密User证书。

openssl verify -verbose -CAfile ca.crt user.crt

生成服务端证书(非必须)

这里也可以不自签,而使用let's encrypt等网站申请SSL证书,避免浏览器提示链接不安全。

步骤与生成用户证书基本相同

1.首先生成服务端私钥,文件名常用 <website-domain-name>.<key>的格式。

openssl genrsa -out vs.antiy.cn.key 4096

2.使用上面的私钥生成CSR。

openssl req -new -key vs.antiy.cn.key -out vs.antiy.cn.csr

我们设置Organization NameServer,且Common Name为域名vs.antiy.cn

3.接下来使用CSR(证书签署请求)和CA相关文件,生成CRT证书。

openssl x509 -req -days 3650 -sha256 -in vs.antiy.cn.csr -CA ca.crt -CAkey ca.key -set_serial 1 -out vs.antiy.cn.crt

至此,我们完成了准备工作,在文件夹下得到了如下文件。

ca.key
ca.crt
ca.pem
user.key
user.csr
user.crt
user.pfx
vs.antiy.cn.key
vs.antiy.cn.csr
vs.antiy.cn.crt

Nginx中配置双向验证

Nginx的安装,请参考官网或搜索引擎,推荐使用Docker进行启动。

1.将域名解析到你的服务器IP上。

​ 如果你真实拥有这个域名,添加一条DNS的A记录即可。

​ 如果你只是想复现双向验证,你当然也可以添加一条HOST来进行测试。

127.0.0.1 vs.antiy.cn

2.拷贝文件

你可以将证书文件拷贝到/etc/nginx/certs下,并且记得给与正确的权限。

然后我们最好不要改动默认的nginx配置,而选择新建一个conf文件在/etc/nginx/conf.d下。

这里给出一个参考,并加入了详细的说明。

server {
    # 监听443端口
    listen  443;

    # 开启SSL
    ssl on;

    # 网站域名
    server_name vs.antiy.cn;

    # 见 https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ssl_server_name
    proxy_ssl_server_name on;

    # 服务端证书
    ssl_certificate      /etc/nginx/certs/vs.antiy.cn.crt;

    # 服务端证书私钥
    ssl_certificate_key /etc/nginx/certs/vs.antiy.cn.key;

    # Important: 
    # 这是验证客户端/用户所用的 CA 证书
    # 在我们的例子中,因为服务器和客户端证书是从同一个 CA 生成,我们使用 ca.crt。
    # 但在实际生产中,Client证书可能是从不同的 CA 创建。
    ssl_client_certificate /etc/nginx/certs/ca.crt;

    # 开启双向验证
    ssl_verify_client on;

    # 要验证的中间证书数量。
    # 具体可参考: https://cheapsslsecurity.com/p/what-is-ssl-certificate-chain/
    ssl_verify_depth 2;

    # 错误日志路径
    error_log /var/log/nginx/error.log debug;

    ssl_prefer_server_ciphers on;
    ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK';

    keepalive_timeout 10;
    ssl_session_timeout 5m;

    # 匹配网站根目录
    location / {
        # 提供网站服务的路径,按需更换。
        root /usr/share/nginx/html;
        index index.html index.htm;
    }
}

上传保存后,重启nginx,就可以开始测试啦

测试使用

直接访问网站,不提供证书,会返回400。

image-20210621141759962

双击pfx文件,就安装证书到机器上,在访问网站时选择个人证书后,便可正常访问。

双向验证,开启成功~

参考链接

how-to-implement-two-way-ssl-with-nginx

what-is-a-pem-file-and-how-does-it-differ-from-other-openssl-generated-key-file


添加新评论