HTTPS 原理与小战
实事求是,不敢写实战,还是改成小战吧。
原理
HTTP + SSL (Secure Socket Layer)
一次浏览器访问,当访问 baidu.com
时浏览器自动添加 schema http://
和 端口 :80
。
这个过程它可能会走这样的路线: 操作系统 -> 路由器 -> ISP -> 电信/联通 -> 城市出口 -> 海底光缆 -> ... -> 联通/电信 -> ISP -> 路由器 -> Server
,这个过程中的每一个网元都有风险。
这就像本地写了一个浏览器的代理,可以抓到任何访问的请求。
要解决的问题:
- C/S 之间的访问加密,让中间网元只传输加密的数据,无法解密(所以要传递密钥)
- 加密需要密钥,传递密钥也应该保密
加密技术
主要有 对称加密算法、非对称加密算法、Hash 算法(摘要算法)。
对称加密算法
常见的有 des、3des(三次 des)、AES、凯撒加密(移位)。(参考百科)
对称加密算法是对称的,即,有对应的解密方法,参数 密钥(相当于盐,掺进数据中)可以影响加密的结果。
非对称加密算法
有两个密钥——公钥和私钥。他们的关系有以下原则:
- 公钥加密的明文,可以用私钥解密
- 私钥加密的明文,可以用公钥解密
- 公钥加密的明文,用公钥不能解密
- 公钥是由私钥生成,且要保证一对多关系
存在的问题:
- 上述特点可以实现 单向 的信息保密,由原则第三条,所以持有公钥发出去的数据是保密的,只能由私钥拥有者解开(原则第一条)且私钥拥有者只有一方(原则第四条)。
- 由问题第一条,可以试想在客户端也拥有自己的私钥/公钥对,将公钥发给服务端,以此来实现 “双向 保密”。但这样是不对的,因为原则第二条,所以非对称加密算法就不能传递数据。
- 由上述问题第一条、第二条,只用非对称加密算法不能保证数据的保密,但它 单向保密 的用处却很实用,可以用它来协商 密钥,由密钥再去而数据做数据加密进行传输。(所以 TLS 只是建链,数据仍是 http 80 端口传输)。
- 还有一个问题就是 中间人 问题,中间人相当于代理,对接客户端时用一对公私钥,对接服务端用另一对公私钥,C/S 无法确认对端是谁,所以还是不安全。
问题的解决:
- 问题第三条中
浏览器中的证书: Internet 属性 - 内容 - 证书
证书从哪里来的: 装上系统就有,公钥是内置在操作系统中的
Hash 算法
Hash 算法可以将数据(入参)映射到一个 固定长度 的值,且一对一映射,无法反向解 Hash 的。
由它,就有了数字签名。就是用 Hash 算法来做数字签名。 Hash算法(公钥) = hash 公钥的签名/摘要
。它的作用只是在 证伪,就是说如果发现某一个数据变了,就证明它被篡改了。
如何保证数据传输的保密性
在非对称加密算法中我们介绍了,数据传输中,只要 Server 的公钥能正确到达 Client 端,Client 端就能验证 Server 端的数据是正确的,且还可以解密这个数据。那问题就在 如何传递公钥 了。
这里引入一个第三方。
我们这样约定:
- Server 端用 第三方的私钥 将自己的 (Server 的)公钥 加密,即得到 密文
- 同时,Server 端用 Hash 算法将 自己的 (Server 的)公钥 签名一下,即生成 摘要
- 同时,准备好自己的 签名算法
这样,由以上三者组成 证书,传递给 Client 端
Client 端拿到证书,也就得到了如上三个值:公钥的密文、 公钥摘要 和 签名算法
- Client 端用 第三方的公钥 将证书中的 密文 解密得到 Server 的公钥
- Client 端用 签名算法 来 Hash 一下 公钥(Server 的),得到自己 Hash 生成的 公钥摘要
- 此时,将自己 Hash 生成的 公钥摘要 与证书中包含的对比,如果一致,则证明是 Server 下发的公钥
那问题就是要确保第三方可信,这个第三方就是 CA,CA 已经保证自己持有私钥,而公钥下发给 Client。客户端的 CA 的公钥 是内置的(注意,不是 Server 的公钥)。
HTTPS 四次握手
浏览器访问 HTTPS -> 访问 Server 443 端口 -> 建立握手(应用层的四次握手)-> 收到数据后开始 HTTP 通信(80 端口)
四次握手
- C->S Hello,我支持 xxx 对称加密算法
- S->C Hello, 好的,我支持 xxx,给你证书 (这个证书是 Server 之前从 CA 申请下来存在 Server 端的,证书中包含自己的公钥、Server 摘要/签名、加密算法,另外还有有效期等)
- C->S 好的,证书没问题,我看到 公钥 了,给你个随机数,我们之后用这个 密钥 这就是协商加解密
- S->C OK,收到
- C<->S 通过 密钥 做对称加密,开始通信
假设中间人拦截到了证书,可以拿到 Server 的公钥,还拦截到了密钥,但这样也无济于事,因为只有私钥可以解密看到密钥。
这其中:1. CA 的私钥是保密的;2. 证书中有签名服务器的名称,且正规 CA 机构保证了它的唯一性(法律问题),所以客户端知道对端是谁;3. 操作系统内置正规的 CA 机构,可以去验证证书。
HTTPS 绝对安全吗
问题一:当首次输入 jd.com
进行访问时,会进行多次 redirect, 第一次是 http://www.jd.com
(默认访问 http), 第二次是到 https://www.jd.com
(服务器主动 redirect)。如果黑客直接写一个假的 www.jd.com 的钓鱼网站,便可以实现拦截。
实战
OpenSSL 生成证书及自签名
OpenSSL 中用到的名词:
- Key,私钥
- CSR,Certificate Signing Request,证书签名请求文件的文件后缀。这个文件相当于用私钥生成的公钥,这个公钥需要被签名。
- CRT,证书
生成服务器私钥
中间会让你输入一个密码(或者说盐值),用于生成私钥
$ openssl genrsa -des3 -out server.key
Generating RSA private key, 2048 bit long modulus (2 primes)
......................................................................+++++
...........+++++
e is 65537 (0x010001)
Enter pass phrase for server.key:
Verifying - Enter pass phrase for server.key:
生成待签名证书
中间要求输入私钥的密码,以及签名信息。
$ openssl req -new -key ./server.key -out pub.csr
Enter pass phrase for ./server.key: # 输入私钥的密码
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]: # 签署人信息
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []: # 这里一般天请求人的服务器域名
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
查看待签名证书
查看待签名证书中的内容
$ openssl req -text -in pub.csr -noout
Certificate Request:
Data:
Version: 1 (0x0)
Subject: C = AU, ST = Some-State, O = Internet Widgits Pty Ltd
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:b9:ee:ff:01:25:7d:49:2f:37:ea:fe:fb:77:e2:
79:db:47:b2:da:33:83:06:25:ed:e2:1e:e9:c0:74:
fc:b6:f9:50:b7:88:b8:5b:43:44:f0:1d:a7:f4:25:
79:ca:28:f8:29:2e:c7:b8:a3:11:7f:e4:8d:7a:f5:
21:60:8b:11:a9:42:ec:1d:96:89:a8:5b:40:f0:1a:
a9:7d:f3:80:b6:53:4a:26:cd:6d:cd:8c:9f:3c:08:
89:5c:89:03:52:ab:8c:0a:d8:e9:46:17:28:3c:e8:
be:30:2b:7d:d5:5c:72:7f:07:be:18:e4:98:a3:86:
97:d5:54:87:a5:b7:6a:7a:cf:c3:74:46:a3:2a:dc:
15:3e:04:61:f4:b6:f7:7d:df:d8:49:86:1c:e2:ff:
4e:aa:2d:72:2a:4c:9d:de:b9:4a:2f:5a:da:5e:7a:
90:c3:80:c6:d6:e8:b7:f8:ef:e5:c7:03:80:8d:91:
8a:84:ef:af:cd:0b:6e:a4:9c:17:4b:2e:43:44:04:
56:fd:20:2a:77:27:ab:95:1d:b4:b4:f7:54:de:c5:
2a:56:9d:a3:f5:fc:65:e4:46:7a:1f:1c:93:8a:9c:
14:33:33:05:31:54:60:47:ee:8f:13:d8:fa:b1:2c:
b2:ca:7c:c7:db:d2:2e:82:e8:3d:f5:87:26:96:08:
08:65
Exponent: 65537 (0x10001)
Attributes:
a0:00
Signature Algorithm: sha256WithRSAEncryption
25:d9:ff:94:f0:8a:93:73:d5:18:73:9d:8f:71:80:ed:9e:38:
fb:ad:d5:e1:54:8c:73:76:b4:0b:4d:21:67:ee:c9:e6:ef:73:
88:cf:42:74:36:b4:bb:7c:4a:bb:41:7a:75:71:8a:6d:68:14:
47:f9:41:8e:83:19:f8:f7:bf:9b:9e:7a:af:4f:db:3e:dc:b5:
ef:8a:6a:a1:17:49:50:7b:53:73:54:42:e9:13:ee:7c:87:c0:
7e:1c:42:2a:70:7f:74:5b:b1:a3:e0:29:a7:82:86:17:38:d3:
9b:74:9d:b1:b2:e2:b1:c8:54:b6:21:a6:28:ce:5e:5e:0b:b0:
11:0f:02:16:81:e3:1a:23:a7:8e:eb:54:59:6c:e5:80:d5:72:
4e:32:94:64:38:ce:17:07:6f:81:c3:88:00:37:14:36:c4:a3:
ea:73:51:d0:eb:92:31:72:45:4c:a8:22:9a:5c:ea:c5:26:6d:
f5:ce:e5:e1:7e:e2:e9:51:84:1e:02:8c:f7:ee:05:f5:d0:8b:
85:67:23:8d:e3:8f:0d:94:b9:d0:76:51:8c:45:98:c2:f7:06:
89:fc:0b:2c:44:79:cb:a8:60:06:c4:64:8b:04:24:de:c9:eb:
03:aa:dc:57:a1:3b:dd:11:8e:65:5a:fd:97:a5:d3:3e:94:ac:
8e:df:32:87
由于签名请求需要 CA 来做,所以我们要搞一个 CA,这就是自建 CA
自建 CA
- 先生成一个 CA 的私钥
openssl genrsa -out ca.key
- 生成一个签名请求
openssl req -new -key ca.key -out ca.csr
- 生成 CA 根证书
x509 是个协议,传入私钥以及签名请求。此时就生成了 CA 的根证书。
$ openssl x509 -days 365 -req -in ca.csr -extensions v3_ca -signkey ca.key -out ca.crt
Signature ok
subject=C = AU, ST = Some-State, O = Internet Widgits Pty Ltd
Getting Private key
这里是自建 CA,上节之前是生成的服务器的私钥和签名请求。有了 CA 之后,下面可以继续对服务器进行签名。
windows 上查看根证书
可以在开始菜单右键“运行”菜单中输入certmgr.msc
参考安装根证书
双击根证书,安装到 受信任的根证书颁发机构。(安装后的效果:浏览器不会再拦截此 https 请求的访问,但在浏览器 url 上会显示红色 不安全 三个字)
对服务器签名请求进行签名
- pub.csr 是 服务端的待签名文件
- ca.key 是 CA 的私钥
- ca.crt 是 CA 的证书
- 签名后的服务器的签名文件是 server.crt
$ openssl x509 -days 365 -req -in ./pub.csr -extensions v3_req -CAkey ca.key -CA ca.crt -CAcreateserial -out server.crt
Signature ok
subject=C = AU, ST = Some-State, O = Internet Widgits Pty Ltd
Getting CA Private Key
Nginx 配置 Https
最简单的配置
server {
listen 443 ssl;
server_name xx.com;
ssl_certificate /path/to/server.crt;
ssl_certificate_key /path/to/server.key;
}
重启服务: service openresty restart
参考
- 公钥与私钥
- 完全图解 HTTPS
- HTTPS详解(读《图解HTTP》笔记)
- SSL/TLS协议运行机制的概述 - 阮一峰
- Golang - Go与HTTPS
- 【百度经验】查看 windows 系统根证书方法
有疑问加站长微信联系(非本文作者)