Https 入门理解

前言

一直对Https的原理只知其一;不知其二,只知道Https比Http协议更安全,可是为何更安全呢?以及怎么具体去部署一个Https呢?都是迷糊状态,经过参考以下文章,对Https有一个入门理解(参考文章以及我的的看法)。javascript

参考资源:html

  1. 图解HTTPS基本原理
  2. HTTPS证书生成原理和部署细节
  3. openssl命令目录

首先放一张图解HTTPS基本原理文章中的图(加了我的的理解注释):java

咱们后面会针对这个图进行一步步的分析。node

下面咱们针对如下两个主题来理解Https:git

  1. 在本地部署https 服务(实践)
  2. 分析https(原理)

本地部署https

咱们须要理解https, 那咱们若是只是针对原理来理解,相信不少环节都串联不起来,看完后最终仍是一头雾水。 因此咱们须要先实践下Https究竟是个什么东西, 到底该怎么部署一个https服务。 参考文章: HTTPS证书生成原理和部署细节算法

生成CA机构

正常的咱们要运行一个Https, 须要向一个CA数字证书认证中心去申请一个咱们的CA证书。可是咱们只是想测试一下Https, 并不可能真的去一个合法的CA机构去申请一个证书,因此咱们可使用自签名 来构建本身的CA机构, 也就是一个能够给本身的服务器颁发证书的机构。shell

下面咱们来看怎么生成一个本身的CA机构。浏览器

  1. 生成CA私钥
openssl genrsa -out ca.key 1024
复制代码

上面的ca.key就是CA机构的私钥文件 关于openssl命令的使用方式能够参考:openssl命令目录安全

  1. 根据CA私钥生成一个CA证书
# a.根据私钥ca.key生成一个新的证书请求文件。其中"-new"表示新生成一个新的证书请求文件,
# "-key"指定私钥文件,"-out"指定输出文件,此处输出文件即为证书请求文件。
openssl req -new -key ca.key -out ca.csr
# x509 表示自签署证书,可用于自建根CA时。
openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt
# 上面两个步骤能够合并为: openssl req -x509 -key ca.key -in ca.csr -out ca.crt -days 365
复制代码

在上面第二步的时候,会有以下的指引:bash

➜  keys  openssl req -new -key ca.key -out ca.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:Zhejiang
Locality Name (eg, city) []:Hangzhou
Organization Name (eg, company) [Internet Widgits Pty Ltd]:My CA
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:localhost
Email Address []:
复制代码

注意:咱们的服务器在向CA申请证书的时候,也会有如上的指引提示, Organization Name (eg, company) [Internet Widgits Pty Ltd] 的值不能同样, 咱们能够给CA机构设置值为My CA, 咱们服务器在申请证书的时候设置的值为My CA Server.

经过上面两个步骤,咱们已经建立了自签名机构。

咱们已经有了CA机构,如今咱们须要给咱们的服务向CA机构申请一个CA证书

申请CA证书

咱们在给咱们的服务申请CA证书的时候, 咱们首先须要给咱们本身的服务建立两个钥匙:公钥私钥

生成步骤以下:

  1. 生成私钥
openssl genrsa -out server.key 1024
复制代码
  1. 生成公钥
openssl rsa -in server.key -pubout -out server.pem
复制代码

上面生成了两个文件: server.keyserver.pem, 咱们在生成公钥的时候,是根据私钥生成的。

咱们已经生成了公钥和私钥了,咱们如今须要向CA机构申请证书了, 能够经过以下的脚本生成:

# 服务器端须要向 CA 机构申请签名证书,在申请签名证书以前依然是建立本身的 CSR 文件
openssl req -new -key server.key -out server.csr
# 向本身的 CA 机构申请证书,签名过程须要 CA 的证书和私钥参与,最终颁发一个带有 CA 签名的证书
openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt
复制代码

上面的server.crt就是咱们服务向CA申请的证书。

咱们能够分析上面的脚本得:

  1. 在向CA申请证书的时候,咱们须要提供咱们服务的公钥(server.key)
  2. 可是上面却没有提供私钥(server.key)

总结:

  1. CA机构是保存了咱们的公钥信息
  2. 咱们服务的私钥信息,只有咱们的服务本身知道,其余人谁也不知道。

在上面咱们已经准备好了自前面CA机构 ,已经咱们服务生成了公钥,私钥,以及向CA申请到了证书了,下面咱们就来看搭建Https服务了。

搭建https服务

咱们经过Nodejs 来搭建一个https服务,其脚本以下(咱们须要将上面生成的文件都放在咱们项目的keys目录下):

// file http-server.js
var https = require('https');
var fs = require('fs');

var options = {
  key: fs.readFileSync('./keys/server.key'),// 服务器端私钥
  cert: fs.readFileSync('./keys/server.crt')  
};

https.createServer(options, function(req, res) {
  res.writeHead(200);
  res.end('hello world 8000');
}).listen(8000, () => {
  console.log(`服务器启动:localhost:8000`)
});
复制代码

接下来咱们能够经过node http-server.js来启动咱们的服务了,咱们能够在浏览器打开https://localhost:8000/

咱们能够看到以下的效果:

看到上面的效果表面咱们的https服务搭建成功了,之因此浏览器显示不安全,是由于浏览器只承认其内置的CA证书, 但这不影响咱们学习。

咱们点击上面的证书,而后查看Certification Path 选项:

发现根证书不被信任,那咱们怎么可让浏览器信任咱们的自签名CA呢, 我么能够按照以下操做:

  1. 按以下图选择网站设置:
  2. 选择隐私和安全性,而后选择管理证书:

  1. 选择"Trusted Root Certification Authoritities"(信任的根证书机构), 而后选择Import(导入),选择咱们上面步骤生存的ca.crt 文件,进行安装。安装完成后,咱们能够再次查看咱们的证书:

发现咱们的证书已经被浏览器信任了.

分析https(原理)

上面咱们已经简单搭建了一个自签名的https服务,咱们已经已经知道一些基本名词: 私钥,公钥,CA,申请CA证书。下面咱们就根据上面咱们贴的图片来解释https运行的基本原理。

①:通常【客户端】首先发起请求,例如请求网站https://www.thinktxt.com/, 生成一个随机数(RandomC),携带支持的TLS版本、加密算法等信息发送至【服务端】

②:【服务端】收到请求, 返回证书、一个随机数( RandomS)、 协商加密算法。这个时候,【服务端】已经保存了两个随机数: RandomCRandomS. 服务器端这个时候发送给客户端的 RandomS是未加密的明文。

③:【客户端】拿到证书后开始进行校验,验证其合法性。

客户端经过本地浏览器或操做系统内置的权威第三方认证机构的CA证书进行验证,一个证书包含域名、证书编号、公钥、有效期等信息(这里是指浏览器内置的CA机构,已经保存了咱们服务的证书的相关信息).

证书编号是在服务器管理员经过第三方证书机构申请证书的时候,第三方机构用他们的私钥对证书编号进行加密存入证书,

上面一句话能够根据咱们上面申请CA证书的里的步骤进行理解:

# 服务器端须要向 CA 机构申请签名证书,在申请签名证书以前依然是建立本身的 CSR 文件
openssl req -new -key server.key -out server.csr
# 向本身的 CA 机构申请证书,签名过程须要 CA 的证书和私钥参与,最终颁发一个带有 CA 签名的证书
openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt
复制代码

证书编号: 能够理解我上面脚本生成的server.crt的编号。 在上面的脚本中,用到的ca.key文件, 这个文件就是CA的私钥

根据编号生成方法生成证书编号证书自己携带了生成证书编号的方法),

CA证书公钥解密得出的证书编号进行对比,验证不经过或者证书过时等状况就提示存在风险(浏览器的红色警告),验证经过则进行下一步。

这里是指咱们浏览器内置的CA保存咱们服务的CA证书的编号,可是经过ca.key私钥加密过的, 咱们在验证证书编号是否合法的时候,咱们再经过浏览器内置的CA的公钥 对CA里面保存的编号进行解密,用解密后的证书编号和服务器返回来的证书编号进行匹配。

④:【客户端】生成一个随机数(PreMaster Key),此时已经有第三个随机数了,根据三个随机数(RandomC、RandomS、PreMaster Key)按照双方约定的算法生成用于后面会话的同一把的“会话密钥”。

可是这个时候生成的“会话密钥” 知识在客户端生成保存起来,服务器这个时候仍是没有第三个随机数PreMaster Key, 服务器要想生成相同的“会话密钥”, 则必须同时也知晓一样的三个随机数,因此如今的问题就是怎么将第三个随机数PreMaster Key传给服务器。

⑤:【客户端】将随机数(PreMaster Key)经过公钥加密后发送至【服务端】(这个步骤只是传递了加密后的随机数PreMaster Key, 会话密钥并无发送到服务端,由于须要服务端根据只有本身知道的私钥去解密PreMaster Key, 而后生成对应的会话密钥 )。

  1. 在这里的公钥 就是咱们服务端申请的CA证书里面的内置的公钥,也就是咱们服务器在申请CA证书时候生成的公钥。经过公钥加密的数据,只有对应的私钥才能解密, 而这个私钥只有咱们的服务端才知道,即便是CA机构都不知道的
  1. 咱们在①② 中传递的随机数RandomC、RandomS 都是明文传递的,这里为何须要加密呢?由于咱们已经明文传递了两个随机数,若是第三个随机数也明文传递, 那都是能够被第三方拦截处理的。

⑥:【服务端】收到密文后用私钥进行解密,获得随机数(PreMaster Key),此时服务端也拥有了三个随机数,根据三个随机数按照事先约定的加密算法生成用于后面会话的同一把的“会话密钥”。

此时在服务端生成的会话密钥 和④ 中浏览器生成的会话密钥是同样的啦。

⑦:【服务端】计算此前全部内容的握手消息hash值,并用“会话密钥”加密后发送至客户端用于验证。

这个会话密钥是浏览器和服务端根据三个随机数生成的,并无经过网络传递,第三方是获取不到这个值的,而后经过会话密钥加密数据传递给客户端(其实这个时候能够算是对称加密了,由于浏览器和客户端都已经知道密钥了)

在⑦计算全部的内容的握手消息的hash 值, 并用【会话密钥】加密后发送给客户端。

⑧:【客户端】解密并计算握手消息的hash值,若是与服务端发来的hash一致,此时握手过程结束。

  1. 客户端根据本身在④生成的会话密钥解密收到的消息
  2. 客户端从新计算全部握手消息的hash值
  3. 将解密后的hash 和本身计算的hash 进行判断,若是同样,则算是真正的验证经过了,能够进行正常通讯了

⑨:验证经过后,开始正常的加密通讯。

开始正常的进行通讯了,通讯内容会用会话密钥和以前协商好的加密算法进行加密了。

总结:

  1. 服务端的私钥 只要服务端知道,其余人都不知道
  2. CA证书的校验,是由于客户端(浏览器)内置了全部的承认的CA证书,由于CA证书是客户端(浏览器)内置的,因此不须要出如今网络请求,也就不会出现第三方劫持的状况,因此达到了安全传输保障
  3. CA证书中携带了服务端的公钥, 用公钥加密的数据,只有私钥才能解密,也就是只有服务端才能正确解密
  4. 会话密钥是客户端和服务端生成的,不在网络请求中传输,因此会话密钥是安全的
相关文章
相关标签/搜索