TLS就是SSL的升级版+网络安全——一图看懂HTTPS建立过程——本质上就是引入第三方监管,web服务器需要先生成公钥和私钥,去CA申请,https通信时候浏览器会去CA校验CA证书的有效性

起初是因为HTTP在传输数据时使用的是明文(虽然说POST提交的数据时放在报体里看不到的,但是还是可以通过抓包工具窃取到)是不安全的,为了解决这一隐患网景公司推出了SSL安全套接字协议层,SSL是基于HTTP之下TCP之上的一个协议层,是基于HTTP标准并对TCP传输数据时进行加密,所以HPPTS是HTTP+SSL/TCP的简称。

由于HTTPS的推出受到了很多人的欢迎,在SSL更新到3.0时,IETF对SSL3.0进行了标准化,并添加了少数机制(但是几乎和SSL3.0无差异),标准化后的IETF更名为TLS1.0(Transport Layer Security 安全传输层协议),可以说TLS就是SSL的新版本3.1,并同时发布“RFC2246-TLS加密协议详解”,如果想更深层次的了解TLS的工作原理可以去RFC的官方网站:www.rfc-editor.org,搜索RFC2246即可找到RFC文档!

SSL/TLS 是什么?

SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS 与 SSL 在传输层对网络连接进行加密。

浅谈 HTTPS 协议和 SSL、TLS 之间的区别与关系

为了保护敏感数据在传送过程中的安全,全球许多知名企业采用 SSL 加密机制,也随着数据安全的重要性和趋势,越来越多的网站都开始接入 HTTPS。

最近苹果也强制要求 APP 开发者使用 HTTPS 加密传输,2017 年 1 月 1 日起,苹果公司将强制使用 HTTPS 协议传输。这将意味着什么就不用子凡多去描述了,大家也都该明白。

SSL 协议提供的安全通道有以下三个特性:

  • 机密性:SSL 协议使用密钥加密通信数据。
  • 可靠性:服务器和客户都会被认证,客户的认证是可选的。
  • 完整性:SSL 协议会对传送的数据进行完整性检查。

三、SSL 证书

SSL 证书是数字证书的一种,类似于驾驶证、护照和营业执照的电子副本。因为配置在服务器上,也称为 SSL 服务器证书。

SSL 证书就是遵守 SSL 协议,由受信任的数字证书颁发机构 CA,在验证服务器身份后颁发,具有服务器身份验证和数据传输加密功能。

SSL 证书依据功能和品牌不同分类有所不同,但 SSL 证书作为国际通用的产品,最为重要的便是产品兼容性(即证书根预埋技术),因为他解决了网民登录网站的信任问题,网民可以通过 SSL 证书轻松识别网站的真实身份。

from:https://www.cnblogs.com/mddblog/p/6948980.html

HTTPS建立过程相当复杂,下图为示意图,可以有整体认识,一般我们编程知道这些已足够。

https建立过程

如果你想仿照HTTPS实现类似加密,可以阅读下具体过程,作为参照

准备工作(对应图中prepare1234)

可以看到,在客户端向服务器发起请求前,还有一些准备工作要做,或者说是有一些工作已经做好了。

  • 从CA证书颁发机构,获取数字证书。
    • 服务器:生成一对公私钥S.pub,S.pri,私钥自己保留,用于解密和签名,不能外泄。将公钥S.pub,身份信息,传给CA(Certificate Authority)机构;
    • CA机构:也有公私钥C.pub,C.pri;由S.pub,身份信息另外附加CA签名生成数字证书(签名使用C.pri进行签名)
    • 将数字证书颁发给申请者(服务器)
  • 客户端(比如我们经常使用的浏览器),为了安全性,会内置一份CA根证书,它包含公钥C.pup,用于对数字证书验证

发起链接

https使用的是443端口,而http使用的是80端口

TCP端口号是一个2字节的整型,处于TCP报文段的前四个字节(2字节源端口号,2字节目的端口号)。

很明显范围是0~65535。其中0~1023具有特殊意义,已经被绑定,比如上面说的443,80,还有ftp的21端口。从1024~49151也具有特殊含义,但是还没有被用完,比如8080端口重定向。剩下的我们就可以随便使用,自定义了。

其实之前在嵌入式开发中,没有连接外网,也没有使用浏览器等等这些。所以端口完全自定义随便用,不用担心冲突:)。

下面的过程为具体详细一点的过程,如果不想看,可以完全只看示意图即可,对我们平时开发用处并不大。或者你在用wireshark类似的抓包工具时看的抓狂不认识,可以看看(反正我用Charles抓包):

1 客户端发起请求(对应图中1)

同样需要三次握手,建立TCP连接(毫无疑问HTTPS也是基于TCP的)

2 客户端发送Client Hello包(对应图中2)

  • 随机数

里面有1970年1月1日到现在的秒数,后面还有一个客户端发来的随机数Client.random

  • Session ID

如果客户端与服务器费尽周折建立了一个HTTPS链接,刚建完就断了,也太可惜,所以用Session ID将其保存,如果下次再来可以直接使用之前的链接进行对话(对称密钥)。

  • 密文族

告诉服务器,自己支持的加密算法种类

  • Server_name

3 Server Hello(对应图中2)

  • 随机数:对应服务器时间,服务器sever.random
  • Seesion ID,如果客户端发给服务器的session ID在服务端有缓存,服务端会尝试使用这个session;否则服务器会启用新的并返回给客户端;
  • 服务器挑选一个密文族

4 Certificate(对应图中2)

服务器终于发来我们想要的数字证书,包含了:签发机构、过期时间、主题名称、公共密钥信息、指纹信息等等

证书信息

5 Server Hello Done(对应图中2)

服务器发送结束

6 客户端验证(对应图中3)

客户端从内置的CA根证书获取C.pub,对服务器发送来的数字证书进行验签,如果一致,说明证书是CA颁发的(前提是C.pub是真实的,确实是CA机构的公钥)。然后看看证书是否过期,域名是否匹配

7 生成对称密钥(对应图中4、5、6)

客户端根据之前的:Client.random + sever.random + pre-master生成对称密钥

经过S.pub加密发送给服务器,之后即可通过对称密钥进行通讯。(就是之前我们熟悉的http)

最后

在整个过程中,一共涉及2对公私密钥对,一对由服务器产生,主要用于加密,一对由CA产生,主要用于签名。

为什么要多一个CA呢?

假设没有CA,那么如果服务器返回的包含公钥的包被hack截取,然后hack也生成一对公私钥,他将自己的公钥发给客户端。hack得到客户端数据后,解密,然后再通过服务器的公钥加密发给服务器,这样数据就被hack获取。

有了CA后,客户端根据内置的CA根证书,很容易识别出hack的公钥不合法,或者说hack的证书不合法。

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.实现:

生成密钥、证书

第一步,为服务器端和客户端准备公钥、私钥

  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 证书

  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 -out ca.crt
  7.  

在执行第二步时会出现:

  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.com 。

第三步,生成服务器端证书和客户端证书

  1. # 服务器端需要向 CA 机构申请签名证书,在申请签名证书之前依然是创建自己的 CSR 文件
  2. openssl req - new -key server.key -out server.csr
  3. # 向自己的 CA 机构申请证书,签名过程需要 CA 的证书和私钥参与,最终颁发一个带有 CA 签名的证书
  4. openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt
  5.  
  6. # client 端
  7. openssl req - new -key client.key -out client.csr
  8. # client 端到 CA 签名
  9. openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in client.csr -out client.crt

此时,我们的 keys 文件夹下已经有如下内容了:

  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. ├── client.crt
  11. ├── client.csr
  12. ├── client.key
  13. ├── client.pem
  14. ├── server.crt
  15. ├── server.csr
  16. ├── server.key
  17. └── server.pem

 

看到上面两个 js 文件了么,我们来跑几个demo。

 

HTTPS本地测试

服务器代码:

  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( './keys/server.crt')
  8. };
  9.  
  10. https.createServer(options, function(req, res) {
  11. res.writeHead( 200);
  12. res.end( 'hello world');
  13. }).listen( 8000);

短短几行代码就构建了一个简单的 https 服务器,options 将私钥和证书带上。然后利用 curl 测试:

  1. ➜ https curl https: //localhost:8000
  2. curl: ( 60) SSL certificate problem: Invalid certificate chain
  3. More details here: http: //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.

当我们直接访问时, curl https://localhost:8000

 一堆提示,原因是没有经过 CA 认证,添加 -k 参数能够解决这个问题:

 

  1. ➜ https curl -k https: //localhost:8000
  2. hello world%

这样的方式是不安全的,存在我们上面提到的中间人攻击问题。可以搞一个客户端带上 CA 证书试试:

  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( './keys/client.crt'),
  12. ca: [fs.readFileSync( './keys/ca.crt')]
  13. };
  14.  
  15. options.agent = new https.Agent(options);
  16.  
  17. var req = https.request(options, function(res) {
  18. res.setEncoding( 'utf-8');
  19. res.on( 'data', function(d) {
  20. console.log(d);
  21. });
  22. });
  23. req.end();
  24.  
  25. req.on( 'error', function(e) {
  26. console.log(e);
  27. });

先打开服务器 node http-server.js ,然后执行

  1. ➜ https node https-client.js
  2. hello world

如果你的代码没有输出 

hello world ,说明证书生成的时候存在问题。也可以通过浏览器访问:

 

\

提示错误:

此服务器无法证明它是localhost;您计算机的操作系统不信任其安全证书。出现此问题的原因可能是配置有误或您的连接被拦截了。

原因是浏览器没有 CA 证书,只有 CA 证书,服务器才能够确定,这个用户就是真实的来自 localhost 的访问请求(比如不是代理过来的)。

你可以点击 继续前往localhost(不安全) 这个链接,相当于执行 curl -k https://localhost:8000 。如果我们的证书不是自己颁发,而是去靠谱的机构去申请的,那就不会出现这样的问题,因为靠谱机构的证书会放到浏览器中,浏览器会帮我们做很多事情。初次尝试的同学可以去 startssl.com 申请一个免费的证书。

 

ca证书

CA 也拥有一个证书(内含 公钥私钥)。网上的公众用户通过验证 CA 的签字从而信任 CA ,任何人都可以得到 CA 的证书(含公钥),用以验证它所签发的证书。
如果用户想得到一份属于自己的证书,他应先向 CA 提出申请。在 CA 判明申请者的身份后,便为他分配一个公钥,并且 CA 将该公钥与申请者的身份信息绑在一起,并为之签字后,便形成证书发给申请者。
如果一个用户想鉴别另一个证书的真伪,他就用 CA 的公钥对那个证书上的签字进行验证,一旦验证通过,该证书就被认为是有效的。证书实际是由证书签证机关(CA)签发的对用户的公钥的认证。
证书的内容包括: 电子签证机关的信息、 公钥用户信息、公钥、权威机构的签字和有效期等等。目前,证书的格式和验证方法普遍遵循X.509 国际标准。

HTTPS建立过程相当复杂,下图为示意图,可以有整体认识,一般我们编程知道这些已足够。

https建立过程

如果你想仿照HTTPS实现类似加密,可以阅读下具体过程,作为参照

准备工作(对应图中prepare1234)

可以看到,在客户端向服务器发起请求前,还有一些准备工作要做,或者说是有一些工作已经做好了。

  • 从CA证书颁发机构,获取数字证书。
    • 服务器:生成一对公私钥S.pub,S.pri,私钥自己保留,用于解密和签名,不能外泄。将公钥S.pub,身份信息,传给CA(Certificate Authority)机构;
    • CA机构:也有公私钥C.pub,C.pri;由S.pub,身份信息另外附加CA签名生成数字证书(签名使用C.pri进行签名)
    • 将数字证书颁发给申请者(服务器)
  • 客户端(比如我们经常使用的浏览器),为了安全性,会内置一份CA根证书,它包含公钥C.pup,用于对数字证书验证

发起链接

https使用的是443端口,而http使用的是80端口

TCP端口号是一个2字节的整型,处于TCP报文段的前四个字节(2字节源端口号,2字节目的端口号)。

很明显范围是0~65535。其中0~1023具有特殊意义,已经被绑定,比如上面说的443,80,还有ftp的21端口。从1024~49151也具有特殊含义,但是还没有被用完,比如8080端口重定向。剩下的我们就可以随便使用,自定义了。

其实之前在嵌入式开发中,没有连接外网,也没有使用浏览器等等这些。所以端口完全自定义随便用,不用担心冲突:)。

下面的过程为具体详细一点的过程,如果不想看,可以完全只看示意图即可,对我们平时开发用处并不大。或者你在用wireshark类似的抓包工具时看的抓狂不认识,可以看看(反正我用Charles抓包):

1 客户端发起请求(对应图中1)

同样需要三次握手,建立TCP连接(毫无疑问HTTPS也是基于TCP的)

2 客户端发送Client Hello包(对应图中2)

  • 随机数

里面有1970年1月1日到现在的秒数,后面还有一个客户端发来的随机数Client.random

  • Session ID

如果客户端与服务器费尽周折建立了一个HTTPS链接,刚建完就断了,也太可惜,所以用Session ID将其保存,如果下次再来可以直接使用之前的链接进行对话(对称密钥)。

  • 密文族

告诉服务器,自己支持的加密算法种类

  • Server_name

3 Server Hello(对应图中2)

  • 随机数:对应服务器时间,服务器sever.random
  • Seesion ID,如果客户端发给服务器的session ID在服务端有缓存,服务端会尝试使用这个session;否则服务器会启用新的并返回给客户端;
  • 服务器挑选一个密文族

4 Certificate(对应图中2)

服务器终于发来我们想要的数字证书,包含了:签发机构、过期时间、主题名称、公共密钥信息、指纹信息等等

证书信息

5 Server Hello Done(对应图中2)

服务器发送结束

6 客户端验证(对应图中3)

客户端从内置的CA根证书获取C.pub,对服务器发送来的数字证书进行验签,如果一致,说明证书是CA颁发的(前提是C.pub是真实的,确实是CA机构的公钥)。然后看看证书是否过期,域名是否匹配

7 生成对称密钥(对应图中4、5、6)

客户端根据之前的:Client.random + sever.random + pre-master生成对称密钥

经过S.pub加密发送给服务器,之后即可通过对称密钥进行通讯。(就是之前我们熟悉的http)

最后

在整个过程中,一共涉及2对公私密钥对,一对由服务器产生,主要用于加密,一对由CA产生,主要用于签名。

为什么要多一个CA呢?

假设没有CA,那么如果服务器返回的包含公钥的包被hack截取,然后hack也生成一对公私钥,他将自己的公钥发给客户端。hack得到客户端数据后,解密,然后再通过服务器的公钥加密发给服务器,这样数据就被hack获取。

有了CA后,客户端根据内置的CA根证书,很容易识别出hack的公钥不合法,或者说hack的证书不合法。

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.实现:

生成密钥、证书

第一步,为服务器端和客户端准备公钥、私钥

  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 证书

  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 -out ca.crt
  7.  

在执行第二步时会出现:

  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.com 。

第三步,生成服务器端证书和客户端证书

  1. # 服务器端需要向 CA 机构申请签名证书,在申请签名证书之前依然是创建自己的 CSR 文件
  2. openssl req - new -key server.key -out server.csr
  3. # 向自己的 CA 机构申请证书,签名过程需要 CA 的证书和私钥参与,最终颁发一个带有 CA 签名的证书
  4. openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt
  5.  
  6. # client 端
  7. openssl req - new -key client.key -out client.csr
  8. # client 端到 CA 签名
  9. openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in client.csr -out client.crt

此时,我们的 keys 文件夹下已经有如下内容了:

  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. ├── client.crt
  11. ├── client.csr
  12. ├── client.key
  13. ├── client.pem
  14. ├── server.crt
  15. ├── server.csr
  16. ├── server.key
  17. └── server.pem

 

看到上面两个 js 文件了么,我们来跑几个demo。

 

HTTPS本地测试

服务器代码:

  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( './keys/server.crt')
  8. };
  9.  
  10. https.createServer(options, function(req, res) {
  11. res.writeHead( 200);
  12. res.end( 'hello world');
  13. }).listen( 8000);

短短几行代码就构建了一个简单的 https 服务器,options 将私钥和证书带上。然后利用 curl 测试:

  1. ➜ https curl https: //localhost:8000
  2. curl: ( 60) SSL certificate problem: Invalid certificate chain
  3. More details here: http: //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.

当我们直接访问时, curl https://localhost:8000

 一堆提示,原因是没有经过 CA 认证,添加 -k 参数能够解决这个问题:

 

  1. ➜ https curl -k https: //localhost:8000
  2. hello world%

这样的方式是不安全的,存在我们上面提到的中间人攻击问题。可以搞一个客户端带上 CA 证书试试:

  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( './keys/client.crt'),
  12. ca: [fs.readFileSync( './keys/ca.crt')]
  13. };
  14.  
  15. options.agent = new https.Agent(options);
  16.  
  17. var req = https.request(options, function(res) {
  18. res.setEncoding( 'utf-8');
  19. res.on( 'data', function(d) {
  20. console.log(d);
  21. });
  22. });
  23. req.end();
  24.  
  25. req.on( 'error', function(e) {
  26. console.log(e);
  27. });

先打开服务器 node http-server.js ,然后执行

  1. ➜ https node https-client.js
  2. hello world

如果你的代码没有输出 

hello world ,说明证书生成的时候存在问题。也可以通过浏览器访问:

 

\

提示错误:

此服务器无法证明它是localhost;您计算机的操作系统不信任其安全证书。出现此问题的原因可能是配置有误或您的连接被拦截了。

原因是浏览器没有 CA 证书,只有 CA 证书,服务器才能够确定,这个用户就是真实的来自 localhost 的访问请求(比如不是代理过来的)。

你可以点击 继续前往localhost(不安全) 这个链接,相当于执行 curl -k https://localhost:8000 。如果我们的证书不是自己颁发,而是去靠谱的机构去申请的,那就不会出现这样的问题,因为靠谱机构的证书会放到浏览器中,浏览器会帮我们做很多事情。初次尝试的同学可以去 startssl.com 申请一个免费的证书。

 

ca证书

CA 也拥有一个证书(内含 公钥私钥)。网上的公众用户通过验证 CA 的签字从而信任 CA ,任何人都可以得到 CA 的证书(含公钥),用以验证它所签发的证书。
如果用户想得到一份属于自己的证书,他应先向 CA 提出申请。在 CA 判明申请者的身份后,便为他分配一个公钥,并且 CA 将该公钥与申请者的身份信息绑在一起,并为之签字后,便形成证书发给申请者。
如果一个用户想鉴别另一个证书的真伪,他就用 CA 的公钥对那个证书上的签字进行验证,一旦验证通过,该证书就被认为是有效的。证书实际是由证书签证机关(CA)签发的对用户的公钥的认证。
证书的内容包括: 电子签证机关的信息、 公钥用户信息、公钥、权威机构的签字和有效期等等。目前,证书的格式和验证方法普遍遵循X.509 国际标准。

猜你喜欢

转载自www.cnblogs.com/bonelee/p/9259173.html