https证书的验证过程与⽣成⽅法
1.简洁的解释:
1.服务器⽤RSA⽣成公钥和私钥
2.把公钥放在证书⾥发送给客户端,私钥⾃⼰保存
3.客户端⾸先向⼀个权威的服务器检查证书的合法性,如果证书合法,客户端产⽣⼀段随机数,这个随机数就作为通信的密钥,我们称之为对称密钥,⽤公钥加密这段随机数,然后发送到服务器
4.服务器⽤密钥解密获取对称密钥,然后,双⽅就已对称密钥进⾏加密解密通信了
PS:⾮对称的RSA加密性能是⾮常低的,原因在于寻⼤素数、⼤数计算、数据分割需要耗费很多的CPU周期,所以⼀般的HTTPS连接只在第⼀次握⼿时使⽤⾮对称加密,通过握⼿交换对称加密密钥,在之后的通信⾛对称加密。
2.详细的:
1.浏览器将⾃⼰⽀持的⼀套加密规则发送给⽹站。
2.⽹站从中选出⼀组加密算法与HASH算法,并将⾃⼰的⾝份信息以证书的形式发回给浏览器。证书⾥⾯包含了⽹站地址,加密公钥,以及证书的颁发机构等信息。
3.浏览器获得⽹站证书之后浏览器要做以下⼯作:
a) 验证证书的合法性(颁发证书的机构是否合法,证书中包含的⽹站地址是否与正在访问的地址⼀致等),如果证书受信任,则浏览器栏⾥⾯会显⽰⼀个⼩锁头,否则会给出证书不受信的提⽰。
b) 如果证书受信任,或者是⽤户接受了不受信的证书,浏览器会⽣成⼀串随机数的密码,并⽤证书中提供的公钥加密。
c) 使⽤约定好的HASH算法计算握⼿消息,并使⽤⽣成的随机数对消息进⾏加密,最后将之前⽣成的所有信息发送给⽹站。
4.⽹站接收浏览器发来的数据之后要做以下的操作:
a) 使⽤⾃⼰的私钥将信息解密取出密码,使⽤密码解密浏览器发来的握⼿消息,并验证HASH是否与浏览器发来的⼀致。
b) 使⽤密码加密⼀段握⼿消息,发送给浏览器。
5.浏览器解密并计算握⼿消息的HASH,如果与服务端发来的HASH⼀致,此时握⼿过程结束,之后所有的通信数据将由之前浏览器⽣成的随机密码并利⽤对称加密算法进⾏加密。
3.实现:
⽣成密钥、证书
第⼀步,为服务器端和客户端准备公钥、私钥
[java]
1. # ⽣成服务器端私钥
2. openssl genrsa -out server.key 1024
3. # ⽣成服务器端公钥
4. openssl rsa -in server.key -pubout -out server.pem
5.
6.
7. # ⽣成客户端私钥
8. openssl genrsa -out client.key 1024
9. # ⽣成客户端公钥
10. openssl rsa -in client.key -pubout -out client.pem
第⼆步,⽣成 CA 证书
[java]java生成随机数的方法
1. # ⽣成 CA 私钥
2. openssl genrsa -out ca.key 1024
3. # X.509 Certificate Signing Request (CSR) Management.
4. openssl req -new -key ca.key -out ca.csr
5. # X.509 Certificate Data Management.
6. openssl x509 -req -in ca.csr -signkey ca.key -
在执⾏第⼆步时会出现:
[java]
1. ➜ keys openssl req -new -key ca.key -out ca.csr
2. You are about to be asked to enter information that will be incorporated
3. into your certificate request.
4. What you are about to enter is what is called a Distinguished Name or a DN.
5. There are quite a few fields but you can leave some blank
6. For some fields there will be a default value,
7. If you enter '.', the field will be left blank.
8. -----
9. Country Name (2 letter code) [AU]:CN
10. State or Province Name (full name) [Some-State]:Zhejiang
11. Locality Name (eg, city) []:Hangzhou
12. Organization Name (eg, company) [Internet Widgits Pty Ltd]:My CA
13. Organizational Unit Name (eg, section) []:
14. Common Name (e.g. server FQDN or YOUR name) []:localhost
15. Email Address []:
注意,这⾥的Organization Name (eg, company) [Internet Widgits Pty Ltd]:后⾯⽣成客户端和服务器端证书的时候也需要填写,不要写成⼀样
的可以随意写如:My CA, My Server, My Client。
然后Common Name (e.g. server FQDN or YOUR name) []:这⼀项,是最后可以访问的域名,我这⾥为了⽅便测试,写成localhost,如果是为了给我的⽹站⽣成证书,需要写成barretlee。
第三步,⽣成服务器端证书和客户端证书
[java]
1. # 服务器端需要向 CA 机构申请签名证书,在申请签名证书之前依然是创建⾃⼰的 CSR ⽂件
2. openssl req -new -key server.key -out server.csr
3. # 向⾃⼰的 CA 机构申请证书,签名过程需要 CA 的证书和私钥参与,最终颁发⼀个带有 CA 签名的证书
4. openssl x509 -req - -CAkey ca.key -CAcreateserial -in server.csr -
5.
6. # client 端
7. openssl req -new -key client.key -out client.csr
8. # client 端到 CA 签名
9. openssl x509 -req - -CAkey ca.key -CAcreateserial -in client.csr -
此时,我们的 keys ⽂件夹下已经有如下内容了:
[java]
1. .
2. ├── https-client.js
3. ├── https-server.js
4. └── keys
5. ├── ca.crt
6. ├── ca.csr
7. ├── ca.key
8. ├── ca.pem
9. ├── ca.srl
10. ├──
11. ├── client.csr
12. ├── client.key
13. ├── client.pem
14. ├──
15. ├── server.csr
16. ├── server.key
17. └── server.pem
看到上⾯两个 js ⽂件了么,我们来跑⼏个demo。
HTTPS本地测试
服务器代码:
[java]
1. // file http-server.js
2. var https = require('https');
3. var fs = require('fs');
4.
5. var options = {
6. key: fs.readFileSync('./keys/server.key'),
7. cert: fs.readFileSync('./')
8. };
9.
10. ateServer(options, function(req, res) {
11. res.writeHead(200);
12. d('hello world');
13. }).listen(8000);
短短⼏⾏代码就构建了⼀个简单的 https 服务器,options 将私钥和证书带上。然后利⽤ curl 测试:[java]
1. ➜ https curl localhost:8000
2. curl: (60) SSL certificate problem: Invalid certificate chain
3. More details here: curl.haxx.se/docs/sslcerts.html
4.
5. curl performs SSL certificate verification by default, using a "bundle"
6. of Certificate Authority (CA) public keys (CA certs). If the default
7. bundle file isn't adequate, you can specify an alternate file
8. using the --cacert option.
9. If this HTTPS server uses a certificate signed by a CA represented in
10. the bundle, the certificate verification probably failed due to a
11. problem with the certificate (it might be expired, or the name might
12. not match the domain name in the URL).
13. If you'd like to turn off curl's verification of the certificate, use
14. the -k (or --insecure) option.
⼀堆提⽰,原因是没有经过 CA 认证,添加-k参数能够解决这个问题:
[java]
1. ➜ https curl -k localhost:8000
2. hello world%
这样的⽅式是不安全的,存在我们上⾯提到的中间⼈攻击问题。可以搞⼀个客户端带上 CA 证书试试:[java]
1. // file http-client.js
2. var https = require('https');
3. var fs = require('fs');
4.
5. var options = {
6. hostname: "localhost",
7. port: 8000,
8. path: '/',
9. methed: 'GET',
10. key: fs.readFileSync('./keys/client.key'),
11. cert: fs.readFileSync('./'),
12. ca: [fs.readFileSync('./')]
13. };
14.
15. options.agent = new https.Agent(options);
16.
17. var req = quest(options, function(res) {
18. res.setEncoding('utf-8');
19. ('data', function(d) {
20. console.log(d);
21. });
22. });
23. d();
24.
25. ('error', function(e) {
26. console.log(e);
27. });
先打开服务器node http-server.js,然后执⾏
[java]
1. ➜ https node https-client.js
2. hello world
如果你的代码没有输出
hello world,说明证书⽣成的时候存在问题。也可以通过访问:
提⽰错误:
此服务器⽆法证明它是localhost;您计算机的操作不信任其安全证书。出现此问题的原因可能是配置有误或您的连接被拦截了。
原因是浏览器没有 CA 证书,只有 CA 证书,服务器才能够确定,这个⽤户就是真实的来⾃ localhost 的访问请求(⽐如不是代理过来的)。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论