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 端的数据是正确的,且还可以解密这个数据。那问题就在 如何传递公钥 了。
这里引入一个第三方。
我们这样约定:
- 第三方用一个 签名算法 (Hash 算法)将 Server 的公钥 及 Server 的一些信息签名得到 摘要
- 第三方用 第三方的私钥 将摘要加密,得到 数字签名
- 第三方将这个 数字签名、摘要、签名算法 以及 服务的公钥和信息作为 证书 颁发给服务端
Server 可以将这个证书出示给别人,来证明自己的身份。比如颁发给 Client 端
- Client 端用 第三方的公钥 将证书中的 数字签名 解密得到 摘要
- Client 端用证书中的 签名算法 重新算一下 Server 的公钥和其他信息,得到新的 摘要
- 此时,将自己生成的 摘要 与证书中包含的对比,如果一致,则证明是 Server 下发的公钥
那问题就是要确保第三方可信,这个第三方就是 CA,CA 已经保证自己持有私钥,而公钥下发给 Client。客户端的 CA 的公钥 是内置的(注意,不是 Server 的公钥)。
HTTPS颁发证书和验证证书过程HTTPS 四次握手
浏览器访问 HTTPS -> 访问 Server 443 端口 -> 建立握手(应用层的四次握手)-> 收到数据后开始进行通信
四次握手
- 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...:
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:...
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
网友评论