1

前言

在我们不论是对服务器还是客户端进行 HTTPS 进行配置时,首先需要准备好的肯定是相关证书文件了,而证书文件是什么又从哪里可以获取到相关证书,并且它们又是什么关系,最后它们怎么在通讯中起作用呢?可能很多人都不是很系统的清楚这一块;趁现在有空整理出来给大家入门了解下。

名词解释

  • RSA:它是一种非对称的加密算法,里面密钥是一对的,分别是公钥和私钥;一般公钥是由私钥生成的;公钥就是公开的密钥,可以公开给大家的,而私钥则是需要自己保管好的不能公开的密钥;它们互相解密,即用公钥加密用私钥加密,反之亦然。
  • 数字签名:数字签名不是用来加解密数据的,而是用来验证数据正确性,判断是否被篡改,场景就类似在一篇文章上签上自己的名字供给别人验证文章是你撰写的;而数字签名就是利用私钥对原始数据的摘要(Hash 值)进行加密出来的。

Digital Signature diagram zh-CN

  • 数字证书:从名字来说就可以看出来,数字证书和数字签名很相似,但是不要把两者混淆,数字证书的生成是用到了数字签名的技术而已;数字证书一般由可信的权威机构 CA 证书授权(Certificate Authority)中心颁发的。持有人将公钥以及身份信息发送给 CA 机构进行颁发生成证书,证书文件中包括持有人公钥、身份信息以及 CA 机构用其 CA 的私钥对其进行的数字签名(后面握手连接中会用到 CA 自身的数字证书中的公钥对其进行校验,这个证书叫做 CA 根证书,一般都集成在操作系统中),一般是最常见格式由X.509定义。
  • CSR:是 Certificate Signing Request 的缩写,即证书签名请求,这不是证书,可以简单理解成公钥,生成证书时要把这个提交给权威的证书颁发机构。
  • CRT:即 certificate 的缩写,即证书。
  • X.509:是一种证书格式,对 X.509 证书来说,认证者总是 CA 或由 CA 指定的人,一份 X.509 证书是一些标准字段的集合,这些字段包含有关用户或设备及其相应公钥的信息。X.509 的证书文件,一般以 .crt 为后缀名,根据该文件的内容编码格式,可以分为二种格式:PEM - Privacy Enhanced Mail,打开看文本格式以 "-----BEGIN..."、"-----END..." 开头和结尾,内容是 Base64 编码,文件名以 .pem、.crt、.cer 为后缀名;Apache 和 Nginx 服务器偏向于使用这种编码格式;DER - Distinguished Encoding Rules,打开看是二进制格式,不可读,文件名以 .der、.crt、.cer 为后缀名;Java 和 Windows 服务器偏向于使用这种编码格式。从后缀名看出 CER 和 CRT 扩展几乎是同义词。
  • PKCS #12:个人信息交换格式(PFX,也称为PKCS 12)支持安全存储证书、私钥和证书路径中的所有证书。PKCS 12格式是唯一可用于导出证书及其私钥的文件格式。由 Public Key Cryptography Standards #12,PKCS#12 标准定义,以 .pfx、.p12 作为证书文件后缀名。
  • PKCS #7:加密消息语法标准(PKCS #7),PKCS 7 格式支持证书的存储和认证路径中的所有证书。

正文

获取证书

为了获取证书前,我们需要生成自己的一对公钥和私钥。在这里我们会使用到一个叫做 OpenSSL 的工具库。

自签名证书,无 CA 签名

  1. 生成密钥与证书
# 生成私钥文件
$ openssl genrsa -out server.key 2048
# 也可以通过指定加密算法来生成加密的文件,通过 'openssl genrsa -help' 查看支持的算法
$ openssl genrsa -aes128 -out server.key 2048

# 生成证书文件
$ openssl req -new -x509 -days 3650 \
    -subj "/C=CN/L=Guangzhou/O=Guangzhou Example Technology Co., Ltd/CN=example.com" \
    -key server.key -out server.crt

# e.g. 百度的证书中的身份信息
CN = baidu.com  # Common Name(证书所请求的域名)
O = Beijing Baidu Netcom Science Technology Co., Ltd # Organization Name
OU = service operation department   # Organization Unit Name
L = beijing     # Locality Name
S = beijing     # Sate or Province Name
C = CN          # Country Name

CA 签名证书(非机构)

# 生成 CA 根证书
$ openssl genrsa -out ca.key 2048
$ openssl req -new -x509 -days 3650 \
    -subj "/C=CN/L=Guangzhou/O=CA Technology Co., Ltd/CN=XXX Global Root CA" \
    -key ca.key -out ca.crt

# 生成 .csr 证书签名请求文件
$ openssl req -new \
    -subj "/C=CN/L=Guangzhou/O=Guangzhou Example Technology Co., Ltd/CN=example.com" \
    -key server.key \
    -out server.csr
# 使用 CA 根证书颁发服务器证书
$ openssl x509 -req -sha256 \
    -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 \
    -in server.csr \
    -out server.crt

它们的关系与作用

在 HTTP 协议传输下,数据都是以明文进行传输,数据安全性得不到保障;使用 HTTPS 加密通讯后,数据保密和不可篡都得到进一步的保障;根据 HTTPS 服务器不同的配置方式,安全性也是不尽相同,下面就是常见的 3 种方式:

无 CA 签名服务器证书

这种方式需要提前将服务器的证书告知客户端,这样客户端在链接服务器时才能进行对服务器证书认证。

通讯过程(简化)

client ----(tcp three way handshake)-----> server
client ----(Client Hello)-----> server
client <----(Server Hello,public key)----- server
client (通过事先保存本地的 server.crt 和服务器发过来的 server.crt 进行比较)
client ----(客户端生成对称密钥,通过 server.crt 提取 public key 进行加密发送)-----> server
client ----(密钥交换后,按照对称密钥进行加密通讯)-----> server

在复杂的网络环境中,服务器证书的传输本身也是一个非常危险的问题。如果在中间某个环节,服务器证书被监听或替换那么对服务器的认证也将不再可靠。

CA 签名服务器证书

为了避免证书的传递过程中被篡改,可以通过一个安全可靠的 CA 根证书分别对服务器和客户端的证书进行签名。这样客户端或服务器在收到对方的证书后可以通过根证书进行验证证书的有效性。

通讯过程(简化)

client ----(tcp three way handshake)-----> server
client ----(Client Hello)-----> server
client <----(Server Hello,public key)----- server
client (通过 CA 根证书对服务器发过来的 server.crt 进行合法性验证)
client ----(客户端生成对称密钥,通过 public key 进行加密发送)-----> server
client ----(密钥交换后,按照对称密钥进行加密通讯)-----> server

双向 CA 签名证书

上面 2 种都是由客户端单向验证的,这种则是客户端服务器双向相互验证。

客户端通过引入一个 CA 根证书和服务器的名字来实现对服务器进行验证。客户端在连接服务器时会首先请求服务器的证书,然后使用 CA 根证书对收到的服务器端证书进行验证。客户端的证书也采用 CA 根证书签名,服务器端对客户端进行证书认证。

通讯过程(简化)

client ----(tcp three way handshake)-----> server
client ----(Client Hello)-----> server
client <----(Server Hello,public key)----- server
client (通过 CA 根证书对服务器发过来的 server.crt 进行合法性验证)
client ----(客户端生成对称密钥,通过 public key 进行加密发送,并发送客户端 client.crt)-----> server
server (服务端使用 CA 根证书对 client.crt 进行做法性校验)
client ----(密钥交换后,按照对称密钥进行加密通讯)-----> server

这种常见于网银系统等交易系统的网站或者 API 使用,确保客户端携带证书进行访问;当无证书的客户端无法进行访问,当访问时会出现 400 Bad Reques <No required SSL certificate was sent >

浏览器证书导入需要装换为 PKCS #12 证书文件才能导入,命令如下:

openssl pkcs12 -export -inkey client.key -in client.crt -out client.pfx
# 输入口令,导入证书后再请求则会弹出选择证书的选项就正常访问了

Nginx 配置 etc.

从 JKS 文件中提取服务证书

说明:JKS 文件扩展名是 .jks 或 .keystore

  1. 查看jks文件中的entry
keytool -list -keystore server.jks
  1. 将”.jks”转为”.p12”(PKCS12格式的证书库)
keytool -importkeystore -srckeystore server.jks -srcalias tomcat -destkeystore server.p12 -deststoretype PKCS12
  1. 得到配置服务器使用的 server.crtserver.keyca.crt 文件
openssl pkcs12 -in server.p12 -nodes -nocerts -out server.key
openssl pkcs12 -in server.p12 -nodes -nokeys -clcerts -out server.crt
openssl pkcs12 -in server.p12 -nodes -nokeys -cacerts -out ca.crt

使用加密的私钥配置 Nginx 支持 SSL 时,并使用下面命令去除私钥必须的口令(否则 start、reload 都得输入密码)

$ cp server.key server.key.org
$ openssl rsa -in server.key.org -out server.key

Nginx 配置

server {
    listen       443 ssl;
    server_name  localhost;

    ssl                  on;
    ssl_certificate      ../cert/server.crt;
    ssl_certificate_key  ../cert/server.key;
    
    ssl_client_certificate ../cert/ca.crt;
    ssl_verify_client on;

    ssl_session_timeout  5m;

    ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers  ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4:HIGH:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!AESGCM;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;

    location / {
     proxy_redirect off;
     proxy_set_header Host $host;
     proxy_set_header X-Real-IP $remote_addr;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_pass http://localhost:8080;
    }
}

参考


Shach
13 声望0 粉丝