HTTPS的双向认证(二)
这篇文章接着讲解下面架构当中的三张证书的创建过程:
从上面的架构可以看到一共有三张证书:
server.crt
- 「服务端」证书ca.crt
- 「服务端」给「客户端证书」签名用的「根证书」client.crt
- 「客户端」证书,这张证书要用ca.crt
这张根证书签名
上面的证书,有几点需要注意的:
- 上面的证书都有各自配套的密钥,保存在单独的密钥文件里,密钥文件是特别重要的,不能泄露。其中「服务端证书」和「根证书」的密钥保存在服务端,「客户端」证书的密钥保存在客户端。
- 其中
ca.crt
根证书的密钥,不一定放在服务端,也可能放在第三方独立保存,但是不能泄露给客户端。 - 密钥文件是必须要保存好的,但是证书文件是公开的。比如客户端访问服务端的时候,会看到服务端的证书,只有拿到服务端的证书,才能验证服务端的签名机构。
关于证书和密钥的注意点就讲这么多。关于公钥加密,非对称加密的基础知识,不是本文讲解重点,需要大家自己系统学习。本文侧重讲解应用和架构。接下来介绍三张证书的创建过程,以及客户端证书的签名过程。因为篇幅关系,这篇文章只讲「服务端证书」的创建过程,并仔细分析证书内容。
创建服务端证书
使用openssl
来创建一张服务端证书,证书名命名为server.crt
。以下是openssl
的相关命令:
$ openssl req \
-new \
-newkey rsa:4096 \
-days 365 \
-nodes \
-x509 \
-subj "/C=CN/ST=Beijing/L=Beijing/O=Personal/CN=localhost" \
-keyout server.key \
-out server.crt
通过上面的命令,我们创建了服务端证书,证书对应的CN
是localhost
。因此这张证书可以让nginx
用来服务localhost
这个域名。以下是执行命令的过程:
注意上面的命令一共生成了两个文件,一个是server.key
,另一个是server.crt
:
其中server.key
是私钥文件,server.crt
是证书文件,这是一套。要注意私钥是必须要保存好不能泄露出去的,证书后续要配置进nginx服务器,用于出示给客户端,让客户端自己去验证服务端的证书的有效性(比如浏览器会用默认的CA机构列表去验证服务端的证书是不是有效机构签名的)。
创建好服务端证书以后,我们可以看一下证书内容:
可以看到服务端证书的文件内容就是base64
加密的字符串。接下来可以使用openssl
的命令解析证书的内容:
$ openssl x509 -noout -text -in server.crt
上面的命令会打印出来证书的具体内容。命令里面几个options的含义如下:
x509
表明证书是x509
格式的。注意「格式」和「编码」是两回事。格式规定了证书里面所包含的「章节段落」和内容,而编码则是证书的内容保存格式,并且编码分为好几层。关于数字证书的「格式」与「编码」标准,不是本文重点,因此不展开论述。
-noout
参考这篇文章:
里面对noout
选项的说明如下:
The
-noout
switch omits the output of the encoded version of the private key.
最后两个-text
和-in
,一个是让openssl
把读取证书的内容输出到屏幕上,然后-in
选项指定要读区的证书文件。
接下来就是查看上面的openssl
命令输出的具体内容:
可以看到上面的证书当中包含几个段落的内容。重点看下两部分的内容:
Subject: C = CN, ST = Beijing, L = Beijing, O = Personal, CN = localhost
「Subject」是证书的主题内容,也就是证书的机构信息等等。可以看到CN
是localhost
。接下来是这部分内容:
Issuer: C = CN, ST = Beijing, L = Beijing, O = Personal, CN = localhost
「Issuer」是证书的签名机构,可以看到这张证书默认的签名机构就是它自己,所以这是一张「自签名」的证书。
如果我们要让服务端证书被所有的客户端(比如浏览器)默认就信任,那么就要拿这张数字证书去权威机构进行「数字签名」,这样issuer
就会变成权威机构。而权威机构的数字证书列表都在各种客户端的默认信任机构列表里,比如chrome浏览器在macOS的环境下默认使用操作系统的机构证书列表:
这些都是默认的权威机构,可以看到这些证书叫做「系统根证书」:
「根证书」也可以叫叫「CA证书」、「机构证书」。我们自己的证书被这些机构签名以后,默认就会被主流的浏览器,工具(比如openssl)信任。因为它们都会维护一个默认的权威机构证书列表。
那么我们在demo场景下,就使用服务端自签名证书就可以了。然后在客户端访问服务端的时候,使用服务端证书本身作为权威机构证书(CA)就可以了。自签名证书都是自己即自己的issuer,所以权威机构的证书要么是由上级权威机构签名,要么是自签名,取决于机构所在级别。
我们自签名的证书因为不在这样的一个签名的信任链条里,所以默认客户端是不会信任的。所以上网的时候会经常看到弹出一个网站的「证书不可靠」这样的警告。
本系列文章的后续篇章会介绍如何让curl
发起请求的时候,使用「服务端证书」作为客户端的CA机构证书,去验证服务端证书。因为服务端证书是「自签名」的证书,所以自己验证自己就可以了。
接下来可以看一下生成的公钥文件server.key
的内容:
可以看到这里包含的是给证书加密的密钥,也是base64编码的。这个密钥文件一定要保存好不要泄露。一旦私钥文件泄露,那么就等于私钥加密的证书的身份就不能保证了,谁都可以用这个私钥文件伪造一份对应的证书。
我们可以用openssl
命令来查看私钥的内容:
$ openssl pkey -in server.key -text
下面是打印出来的私钥的解码后内容:
注意私钥的这些参数如果泄露,那么私钥就泄露了。
关于服务端证书,要说的就这么多。下一篇文章讲解生成「CA证书」和「客户端证书」的方法,并且使用我们自己生成的「CA证书」给「客户端证书」签名。
- 上一篇 HTTPS的双向认证(一)
- 下一篇 HTTPS的双向认证(三)