HTTPS双向认证指南

原文:https://www.jianshu.com/p/2b2d1f511959

研究HTTPS的双向认证实现与原理,踩了不少坑,终于整个流程都跑通了,现在总结出一篇文档来,把一些心得,特别是容易踩坑的地方记录下来。

1.原理

双向认证,顾名思义,客户端和服务器端都需要验证对方的身份,在建立Https连接的过程中,握手的流程比单向认证多了几步。单向认证的过程,客户端从服务器端下载服务器端公钥证书进行验证,然后建立安全通信通道。双向通信流程,客户端除了需要从服务器端下载服务器的公钥证书进行验证外,还需要把客户端的公钥证书上传到服务器端给服务器端进行验证,等双方都认证通过了,才开始建立安全通信通道进行数据传输。

1.1 单向认证流程

单向认证流程中,服务器端保存着公钥证书和私钥两个文件,整个握手过程如下:

img

单向认证流程

  1. 客户端发起建立HTTPS连接请求,将SSL协议版本的信息发送给服务器端;
  2. 服务器端将本机的公钥证书(server.crt)发送给客户端;
  3. 客户端读取公钥证书(server.crt),取出了服务端公钥;
  4. 客户端生成一个随机数(密钥R),用刚才得到的服务器公钥去加密这个随机数形成密文,发送给服务端;
  5. 服务端用自己的私钥(server.key)去解密这个密文,得到了密钥R
  6. 服务端和客户端在后续通讯过程中就使用这个密钥R进行通信了。

1.2 双向认证流程

img

双向认证流程

  1. 客户端发起建立HTTPS连接请求,将SSL协议版本的信息发送给服务端;
  2. 服务器端将本机的公钥证书(server.crt)发送给客户端;
  3. 客户端读取公钥证书(server.crt),取出了服务端公钥;
  4. 客户端将客户端公钥证书(client.crt)发送给服务器端;
  5. 服务器端使用根证书(root.crt)解密客户端公钥证书,拿到客户端公钥;
  6. 客户端发送自己支持的加密方案给服务器端;
  7. 服务器端根据自己和客户端的能力,选择一个双方都能接受的加密方案,使用客户端的公钥加密8. 后发送给客户端;
  8. 客户端使用自己的私钥解密加密方案,生成一个随机数R,使用服务器公钥加密后传给服务器端;
  9. 服务端用自己的私钥去解密这个密文,得到了密钥R
  10. 服务端和客户端在后续通讯过程中就使用这个密钥R进行通信了。

2. 证书生成

从上一章内容中,我们可以总结出来,如果要把整个双向认证的流程跑通,最终需要六个证书文件:

  • 服务器端公钥证书:server.crt
  • 服务器端私钥文件:server.key
  • 根证书:root.crt
  • 客户端公钥证书:client.crt
  • 客户端私钥文件:client.key
  • 客户端集成证书(包括公钥和私钥,用于浏览器访问场景):client.p12

生成这一些列证书之前,我们需要先生成一个CA根证书,然后由这个CA根证书颁发服务器公钥证书和客户端公钥证书。为了验证根证书颁发与验证客户端证书这个逻辑,我们使用根证书办法两套不同的客户端证书,然后同时用两个客户端证书来发送请求,看服务器端是否都能识别。下面是证书生成的内在逻辑示意图:

img

证书生成

我们可以全程使用openssl来生成一些列的自签名证书,自签名证书没有听过证书机构的认证,很多浏览器会认为不安全,但我们用来实验是足够的。需要在本机安装了openssl后才能继续本章的实验。

2.1生成自签名根证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(1)创建根证书私钥:
openssl genrsa -out root.key 1024

(2)创建根证书请求文件:
openssl req -new -out root.csr -key root.key
后续参数请自行填写,下面是一个例子:
Country Name (2 letter code) [XX]:cn
State or Province Name (full name) []:bj
Locality Name (eg, city) [Default City]:bj
Organization Name (eg, company) [Default Company Ltd]:alibaba
Organizational Unit Name (eg, section) []:test
Common Name (eg, your name or your servers hostname) []:root
Email Address []:a.alibaba.com
A challenge password []:
An optional company name []:

(3)创建根证书:
openssl x509 -req -in root.csr -out root.crt -signkey root.key -CAcreateserial -days 3650

在创建证书请求文件的时候需要注意三点,下面生成服务器请求文件和客户端请求文件均要注意这三点:
根证书的Common Name填写root就可以,所有客户端和服务器端的证书这个字段需要填写域名,一定要注意的是,根证书的这个字段和客户端证书、服务器端证书不能一样;
其他所有字段的填写,根证书、服务器端证书、客户端证书需保持一致
最后的密码可以直接回车跳过。

经过上面三个命令行,我们最终可以得到一个签名有效期为10年的根证书root.crt,后面我们可以用这个根证书去颁发服务器证书和客户端证书。

2.2 生成自签名服务器端证书

1
2
3
4
5
6
7
8
(1)生成服务器端证书私钥:
openssl genrsa -out server.key 1024

(2) 生成服务器证书请求文件,过程和注意事项参考根证书,本节不详述:
openssl req -new -out server.csr -key server.key

(3) 生成服务器端公钥证书
openssl x509 -req -in server.csr -out server.crt -signkey server.key -CA root.crt -CAkey root.key -CAcreateserial -days 3650

经过上面的三个命令,我们得到:

  • server.key:服务器端的秘钥文件
  • server.crt:有效期十年的服务器端公钥证书,使用根证书和服务器端私钥文件一起生成

2.3 生成自签名客户端证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(1)生成客户端证书秘钥:
openssl genrsa -out client.key 1024
openssl genrsa -out client2.key 1024

(2) 生成客户端证书请求文件,过程和注意事项参考根证书,本节不详述:
openssl req -new -out client.csr -key client.key
openssl req -new -out client2.csr -key client2.key

(3) 生客户端证书
openssl x509 -req -in client.csr -out client.crt -signkey client.key -CA root.crt -CAkey root.key -CAcreateserial -days 3650
openssl x509 -req -in client2.csr -out client2.crt -signkey client2.key -CA root.crt -CAkey root.key -CAcreateserial -days 3650


(4) 生客户端p12格式证书,需要输入一个密码,选一个好记的,比如123456
openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12
openssl pkcs12 -export -clcerts -in client2.crt -inkey client2.key -out client2.p12

重复使用上面的三个命令,我们得到两套客户端证书:
client.key/client2.key:客户端的私钥文件
client.crt/client2.key:有效期十年的客户端证书,使用根证书和客户端私钥一起生成
client.p12/client2.p12:客户端p12格式,这个证书文件包含客户端的公钥和私钥,主要用来给浏览器访问使用

3.Nginx配置

有了上面的一些列证书,我们可以在Nginx服务器上配置双向认证的HTTPS服务了,具体配置方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
server {
listen 443 ssl;
server_name www.yourdomain.com;
ssl on;
ssl_certificate /data/sslKey/server.crt; #server公钥证书
ssl_certificate_key /data/sslKey/server.key; #server私钥
ssl_client_certificate /data/sslKey/root.crt; #根证书,可以验证所有它颁发的客户端证书
ssl_verify_client on; #开启客户端证书验证

location / {
root html;
index index.html index.htm;
}
}

具体就是将服务器端的两个证书文件(server.crt/server.key)和根证书文件(root.crt)的路径配置到nginx的server节点配置中,并且把ssl_verify_client这个参数设置为on。

有一点需要注意的就是,如果客户端证书不是由根证书直接颁发的,配置中还需要加一个配置:ssl_verify_depth 1;

配置完成后,执行nginx -s reload重新加载下就生效了。

4.使用curl作为客户端调用验证

使用curl加上证书路径,可以直接测试Nginx的HTTPS双向认证是否配置成功。下面我们测试三个用例:

  • 使用client.crt/client.key这一套客户端证书来调用服务器端
  • 使用client.crt2/client2.key这一套客户端证书来调用服务器端
  • 不使用证书来调用服务器端

下面是三个用例的测试结果:

  • 带证书的成功调用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#--cert指定客户端公钥证书的路径
#--key指定客户端私钥文件的路径
#-k不校验证书的合法性,因为我们用的是自签名证书,所以需要加这个参数
#可以使用-v来观察具体的SSL握手过程

curl --cert ./client.crt --key ./client.key https://integration-fred2.fredhuang.com -k -v
* Rebuilt URL to: https://47.93.245.203/
* Trying 47.93.245.203...
* TCP_NODELAY set
* Connected to 47.93.245.203 (47.93.245.203) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
* CAfile: /etc/ssl/cert.pem
CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS handshake, CERT verify (15):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
* subject: C=CN; ST=BJ; L=BJ; O=Alibaba; OU=Test; CN=integration-fred2.fredhuang.com; emailAddress=a@alibaba.com
* start date: Nov 2 01:01:34 2019 GMT
* expire date: Oct 30 01:01:34 2029 GMT
* issuer: C=CN; ST=BJ; L=BJ; O=Alibaba; OU=Test; CN=root; emailAddress=a@alibaba.com
* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
> GET / HTTP/1.1
> host:integration-fred2.fredhuang.com
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.17.5
< Date: Sat, 02 Nov 2019 02:39:43 GMT
< Content-Type: text/html
< Content-Length: 612
< Last-Modified: Wed, 30 Oct 2019 11:29:45 GMT
< Connection: keep-alive
< ETag: "5db97429-264"
< Accept-Ranges: bytes
<
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
* Connection #0 to host 47.93.245.203 left intact
  • 使用client2.crt/client2.key这一套客户端证书来调用服务器端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
curl --cert ./client2.crt --key ./client2.key https://integration-fred2.fredhuang.com -k
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
  • 不带证书的调用
1
2
3
4
5
6
7
8
9
curl https://integration-fred2.fredhuang.com -k
<html>
<head><title>400 No required SSL certificate was sent</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<center>No required SSL certificate was sent</center>
<hr><center>nginx/1.17.5</center>
</body>
</html>

三个用例都符合预期,从第一个测试日志中,我们可以看到,整个通信过程较长,客户端验证服务器端的证书,客户端也将自己的证书上传到服务器端进行验证。使用根证书颁发的两个客户端证书都可以正常发起双向HTTPS认证的调用。没有带客户端证书的调用会被服务器端拒绝服务。

5.使用Java调用

由于使用的是自签名证书,使用ApacheHttpClient去调用的话,需要将服务器证书加入可信任证书库中,才能成功调用,也可以在代码中简单忽略证书。

1
2
cd $JAVA_HOME
sudo ./bin/keytool -import -alias ttt -keystore cacerts -file /Users/fred/temp/cert5/server.crt

将服务器端公钥证书设置为可信证书后,使用以下代码可以直接发起带客户端证书的HTTPS请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;

public class HttpClientWithClientCert {

private final static String PFX_PATH = "/Users/fred/temp/cert5/client.p12"; //客户端证书路径
private final static String PFX_PWD = "123456"; //客户端证书密码

public static String sslRequestGet(String url) throws Exception {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
InputStream instream = new FileInputStream(new File(PFX_PATH));
try {
keyStore.load(instream, PFX_PWD.toCharArray());
} finally {
instream.close();
}
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, PFX_PWD.toCharArray()).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext
, new String[] { "TLSv1" } // supportedProtocols ,这里可以按需要设置
, null // supportedCipherSuites
, SSLConnectionSocketFactory.getDefaultHostnameVerifier());

CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
try {
HttpGet httpget = new HttpGet(url);
//httpget.addHeader("host", "integration-fred2.fredhuang.com");// 设置一些heander等
CloseableHttpResponse response = httpclient.execute(httpget);
try {
HttpEntity entity = response.getEntity();
String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");//返回结果
EntityUtils.consume(entity);
return jsonStr;
} finally {
response.close();
}
} finally {
httpclient.close();
}
}

public static void main(String[] args) throws Exception {
System.out.println(System.getProperty("java.home"));
System.out.println(sslRequestGet("https://integration-fred2.fredhuang.com"));
}

}

6. 总结

HTTPS双向认证方式通信在一些安全级别较高的场景非常有用,拥有合法证书的客户端才能正常访问业务。实现这个场景需要以下几步:

  • 生成根公钥证书和私钥文件(root.crt/root.key);
  • 使用根证书和根证书私钥(root.crt/root.key)配合服务器端私钥颁发服务器端证书(server.crt);
  • 使用根证书和根证书私钥(root.crt/root.key)配合客户端私钥颁发客户端证书(server.crt);
  • 将根证书(root.crt)、服务器端证书(server.crt)、服务器端秘钥(server.key)配置到Nginx的Server配置中;
  • 客户端使用客户端私钥和根证书颁发的客户端证书(client.crt)正常访问业务。

根证书可以任意颁发客户端证书并给业务方使用,为了安全起见,需要注意颁发的证书的有效期。

魔鬼藏在细节,有两个细节再次重点强调下:

  • 根证书的Common Name填写root就可以,所有客户端和服务器端的证书这个字段需要填写域名,一定要注意的是,根证书的这个字段和客户端证书、服务器端证书不能一样;
  • Nginx的ssl_client_certificate需要配置根证书root.crt,而不是客户端证书;

7.其他

7.1 证书生成1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# CA证书及密钥生成方法一----直接生成CA密钥及其自签名证书
# 如果想以后读取私钥文件ca_rsa_private.pem时不需要输入密码,亦即不对私钥进行加密存储,那么将-passout pass:123456替换成-nodes
openssl req -newkey rsa:2048 -passout pass:123456 -keyout ca_rsa_private.pem -x509 -days 365 -out ca.crt -subj "/C=CN/ST=GD/L=SZ/O=COM/OU=NSP/CN=CA/emailAddress=youremail@qq.com"
# CA证书及密钥生成方法二----分步生成CA密钥及其自签名证书:
# openssl genrsa -aes256 -passout pass:123456 -out ca_rsa_private.pem 2048
# openssl req -new -x509 -days 365 -key ca_rsa_private.pem -passin pass:123456 -out ca.crt -subj "/C=CN/ST=GD/L=SZ/O=COM/OU=NSP/CN=CA/emailAddress=youremail@qq.com"

# 服务器证书及密钥生成方法一----直接生成服务器密钥及待签名证书
# 如果想以后读取私钥文件server_rsa_private.pem时不需要输入密码,亦即不对私钥进行加密存储,那么将-passout pass:server替换成-nodes
openssl req -newkey rsa:2048 -passout pass:server -keyout server_rsa_private.pem -out server.csr -subj "/C=CN/ST=GD/L=SZ/O=COM/OU=NSP/CN=SERVER/emailAddress=youremail@qq.com"
# 服务器证书及密钥生成方法二----分步生成服务器密钥及待签名证书
# openssl genrsa -aes256 -passout pass:server -out server_rsa_private.pem 2048
# openssl req -new -key server_rsa_private.pem -passin pass:server -out server.csr -subj "/C=CN/ST=GD/L=SZ/O=COM/OU=NSP/CN=SERVER/emailAddress=youremail@qq.com"
# 使用CA证书及密钥对服务器证书进行签名:
openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca_rsa_private.pem -passin pass:123456 -CAcreateserial -out server.crt
# 将加密的RSA密钥转成未加密的RSA密钥,避免每次读取都要求输入解密密码
# 密码就是生成私钥文件时设置的passout、读取私钥文件时要输入的passin,比如这里要输入“server”
openssl rsa -in server_rsa_private.pem -out server_rsa_private.pem.unsecure

# 客户端证书及密钥生成方法一----直接生成客户端密钥及待签名证书
# 如果想以后读取私钥文件client_rsa_private.pem时不需要输入密码,亦即不对私钥进行加密存储,那么将-passout pass:client替换成-nodes
openssl req -newkey rsa:2048 -passout pass:client -keyout client_rsa_private.pem -out client.csr -subj "/C=CN/ST=GD/L=SZ/O=COM/OU=NSP/CN=CLIENT/emailAddress=youremail@qq.com"
# 客户端证书及密钥生成方法二----分步生成客户端密钥及待签名证书:
# openssl genrsa -aes256 -passout pass:client -out client_rsa_private.pem 2048
# openssl req -new -key client_rsa_private.pem -passin pass:client -out client.csr -subj "/C=CN/ST=GD/L=SZ/O=COM/OU=NSP/CN=CLIENT/emailAddress=youremail@qq.com"
# 使用CA证书及密钥对客户端证书进行签名:
openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca_rsa_private.pem -passin pass:123456 -CAcreateserial -out client.crt
# 将加密的RSA密钥转成未加密的RSA密钥,避免每次读取都要求输入解密密码
# 密码就是生成私钥文件时设置的passout、读取私钥文件时要输入的passin,比如这里要输入“client”
openssl rsa -in client_rsa_private.pem -out client_rsa_private.pem.unsecure

7.2 证书生成2

制作根证书

1
2
3
4
#1. 生成CA私钥:ca.key (这个是信任的起点,根证书,所有其他的证书都要经过CA的私钥签名)
openssl genrsa -des3 -out ca.key 2048
#2. 生成 CA根证书的公钥:ca.crt
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt

制作服务端证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#1. 生成证服务端书私钥:server.pem
openssl genrsa -des3 -out server.pem 1024

#2. 生成无密码的服务端私钥:server.key
openssl rsa -in server.pem -out server.key

#3. 生成服务端签发请求:server.csr
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. 把ca.crt的内容追加到server.crt后面,因为有些浏览似乎不支持
cat ca.crt >> server.crt

制作客户端证书 (跟制作服务端证书步骤一样)

1
2
3
4
5
6
7
8
9
10
11
#1. 生成客户端证书私钥
openssl genrsa -des3 -out client.pem 2048

#2. 生成客户端证书签发请求
openssl req -new -key client.pem -out client-req.csr

#3. 用CA证书给客户端证书进行签名
openssl x509 -req -sha256 -in client-req.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 -out client.crt

#4. 客户端证书CRT转换为PKCS #12格式(全称应该叫做 Personal Information Exchange,通常以 p12作为后缀)
openssl pkcs12 -export -clcerts -in client.crt -inkey client.pem -out chenbo.p12

nginx配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
server {
listen 443;
server_name www.test.com;
charset koi8-r;
#access_log logs/host.access.log main;

ssl on; #开启ssl
ssl_certificate /root/security/server.crt; #服务端证书位置
ssl_certificate_key /root/security/server.key; #服务器私钥
ssl_session_timeout 5m; #session有效期,5分钟
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ALL:!DH:!EXPORT:!RC4:+HIGH:+MEDIUM:-LOW:!aNULL:!eNULL; #加密算法
ssl_prefer_server_ciphers on;

ssl_verify_client on; #开启客户端验证
ssl_client_certificate /root/security/ca.crt; #CA证书用于验证客户端证书的合法性
ssl_verify_depth 1;
}

7.3 SSL/TLS基本概念

  SSL:Secure Socket Layer(安全套接层协议)的缩写,可以在Internet上提供秘密性传输。它是在上世纪90年代中期,由Netscape公司设计,目前已有3.0版本。为啥要发明 SSL 这个协议呢?因为原先互联网上使用的 HTTP 协议是明文的,内容是不加密的,这样就很可能在内容传播的时候被别人监听到,对于安全性要求较高的场合,必须要加密,https就是带加密的http协议。SSL协议的发明,就解决这些问题。目前SSL有1.0,2.0,3.0。

  TLS:Transport Layer Security(传输层安全协议)。是 SSL的标准化,相当于SSL的升级,可以把SSL看作是windows7,而TLS看作是windows10。很多时候我们把这两者并列称呼 SSL/TLS,因为这两者可以视作同一个东西的不同阶段。HTTPS 协议,说白了就是“HTTP 协议”和“SSL/TLS 协议”的组合。可以把 HTTPS 大致理解为—“HTTP over SSL”或“HTTP over TLS”。目前TLS有1.0,1.1,1.2,其中1.0基于SSL 3.0,修改不大。

  SSL证书:SSL安全协议主要用来提供对用户和服务器的认证;对传送的数据进行加密和隐藏;确保数据在传送中不被改变,即数据的完整性。SSL证书通过在客户端浏览器和Web服务器之间建立一条SSL安全通道,由于SSL技术已建立到所有主要的浏览器和WEB服务器程序中,因此,仅需安装服务器证书就可以激活该功能了。通过它可以激活SSL协议,实现数据信息在客户端和服务器之间的加密传输,可以防止数据信息的泄露。保证了双方传递信息的安全性,而且用户可以通过服务器证书验证他所访问的网站是否是真实可靠。

证书申请文件

  私钥:私钥是一个算法名称加上密码串,用来加解密用的文件或者字符串。

  公钥:公钥也是一个算法名称加上密码串,一般不会单独给别人,而是嵌在证书里面一起给别人。

  密钥:用来加解密用的文件或者字符串。密钥在非对称加密的领域里,指的是私钥和公钥,他们总是成对出现,其主要作用是加密和解密。常用的加密强度是2048bit。

  CA:certificate authority,认证证书的第三方机构,专门用自己的私钥给别人进行签名的单位或者机构

  申请(签名)文件:在公钥的基础上加上一些申请人的属性信息,比如域名、名称、国家、地区以及证书适用于什么场景等信息,然后带上进行的签名,发给CA(私下安全的方式发送),带上自己签名的目的是为了防止别人篡改文件。

  证书文件:证书由公钥加上描述信息,然后经过私钥签名之后得到。一般都是一个人的私钥给另一个人的公钥签名,如果是自己的私钥给自己的公钥签名,就叫自签名。

  签名过程:CA收到申请文件后,会走核实流程,确保申请人确实是证书中描述的申请人,防止别人冒充申请者申请证书,核实通过后,会用CA的私钥对申请文件进行签名,签名后的证书包含申请者的基本信息,CA的基本信息,证书的使用年限,申请人的公钥,签名用到的摘要算法,CA的签名。

证书文件格式

证书的编码格式
  PEM:是Privacy Enhanced Mail的简称,通常用于数字证书认证机构(Certificate Authorities,CA),扩展名为.pem, .crt,,.cer, .key。内容为Base64编码的ASCII码文件,有类似“-----BEGIN CERTIFICATE-----“和 “-----END CERTIFICATE-----“的头尾标记。服务器认证证书,中级认证证书和私钥都可以储存为PEM格式(认证证书其实就是公钥)。Apache和nginx等类似的服务器使用PEM格式证书。

  DER:是Distinguished Encoding Rules的简称,与PEM不同之处在于其使用二进制而不是Base64编码的ASCII。扩展名为.der,但也经常使用.cer用作扩展名,所有类型的认证证书和私钥都可以存储为DER格式。Java和Windows服务器使用DER格式证书。

证书签名请求CSR
  CSR:是Certificate Signing Request的简称,它是向CA机构申请数字证书时使用的请求文件。在生成请求文件前,我们需要准备一对对称密钥。私钥信息自己保存,请求中会附上公钥信息以及国家,城市,域名,Email等信息,CSR中还会附上签名信息。当我们准备好CSR文件后就可以提交给CA机构,等待他们给我们签名,签好名后我们会收到crt文件,即证书。

  CSR并不是证书,而是向权威证书颁发机构获得签名证书的申请。把CSR交给权威证书颁发机构,权威证书颁发机构对此进行签名。保留好CSR,当权威证书颁发机构颁发的证书过期的时候,还可以用同样的CSR来申请新的证书,key保持不变。

证书文件扩展名
  CRT:表示证书,常见于linux系统,可能是PEM编码和DER编码,大多数是PEM编码。

  CER:表示证书,常见于Windows系统,可能是PEM编码和DER编码,大多数是DER编码。

  KEY:存放一个公钥或者私钥,编码可能是PEM或者DER。查看KEY的办法:openssl rsa -in test.key -text -noout

CSR:Certificate Signing Request,证书签名请求,核心内容是一个公钥,在生成这个申请的时候,同时也会生成一个私钥。

  PFX/P12:predecessor of PKCS#12,常用语windows IIS。

  JKS:即Java Key Storage,这是Java的专利。

证书转换
  PEM转为DER:openssl x509 -in cert.crt -outform der -out cert.der

  DER转为PEM:openssl x509 -in cert.crt -inform der -outform pem -out cert.pem

  查看DER格式证书的信息:openssl x509 -in certificate.der -inform der -text -noout