我们先不去探究 ssl 的实现原理,我们先从设计者的角度去思考如何去建立一个安全的传输通道。
1,从第一个消息开始
客户端 A 向服务端 B 发送一条消息,这个消息可能会被拦截以及篡改,我们如何做到 A 发送给B 的数据包,及时被拦截了,也没办法得知消息内容并且也不能查看呢?
2,利用对称加密
要做到消息不能被第三方查看以及篡改,那么第一想法就是对内容进行加密,同时,该消息还需要能被服务端进行解密。所以我们可以使用对称加密算法来实现,密钥 S 扮演着加密和解密的角色。在密钥 S不公开的情况下,就可以保证安全性?
3,没那么简单
在互联网世界,通信不会这么简单,也许是这样
4,协商过程又是不安全的
协商过程,意味着又是基于一个网络传输的情况下去动态分配密钥,可是这个协商过程又是不安全的,怎么破?
5,非对称加密出马
非对称加密算法的特点是:私钥加密后的密文,只要有公钥,都能解密,但是公钥加密后的密文,只有私钥可以解密。私钥只有一个人有,而公钥可以发给所有人。
6,公钥怎么拿?
使用非对称加密算法,那么如何让 A、B 客户端安全地持有公钥? 那么我们逐步思考,有两种我们能想到的方案:
- 服务器端将公钥发送给每一个客户端
- 服务器端将公钥放到一个远程服务器,客户端可以请求到 (多了一次请求,还得解决公钥放置问题)
方案一似乎不可行,因为,传输过程又是不安全的?公钥可能会被调包
7,引入第三方机构
到上面这一步,最关键的问题是,客户端如何知道给我公钥的是黄蓉还是小龙女?只能找本人去证实?或者有一个第三者来帮你证实,并且第三者是绝对公正的。 所以,引入一个可信任的第三者是一个好的方案 服务端把需要传递给客户端的公钥,通过第三方机构提供的私钥对公钥内容进行加密后,再传递给客户端? 通过第三方机构私钥对服务端公钥加密以后的内容,就是一个简陋版本的 “数字证书”。这个证书中包含【服务器公钥】
8,如果不法分子也拿到证书
如果不法分子也申请了证书,那它可以对证书进行调包。客户端在这种情况下是无法分辨出收到的是你的证书,还是中间人的。因为不论是中间人的、还是你的证书都能使用第三方机构的公钥进行解密。
9,验证证书的有效性
事情发展到现在,问题演变成了,客户端如何识别证书的真伪?在现实生活中,要验证一个东西的真伪,绝大部分都是基于编号去验证(比如大学毕业证书,比如买的数码产品是否是山寨),我之前讲过,计算机领域的解决方案都是人为去实现的,所以在这里,解决方案也是一样,如果给这个数字证书添加一个证书编号?是不是就能达到目的呢? 证书上写了如何根据证书的内容生成证书编号。客户端拿到证书后根据证书上的方法自己生成一个证书编号,如果生成的证书编号与证书上的证书编号相同,那么说明这个证书是真实的。 这块有点类似于 md5 的验证,我们下载一个软件包,都会提供一个 md5 的值,我们可以拿到这个软件包以后通过一个第三方软件去生成一个 md5 值去做比较,是不是一样如果一样表示这个软件包没被篡改过
10,第三方机构的公钥证书存哪里?
浏览器和操作系统都会维护一个权威的第三方机构列表(包括他们的公钥) 因为客户端接收到的证书中会些颁发机构,客户端就根据这个颁发机构的值在本地找到响应的公钥。 说到这里,我想大家一定知道,证书就是 HTTPS 中的数字证书,证书编号就是数字签名,而第三方机构就是数字证书的签发机构(CA)
个人思考:针对最后面客户端从浏览器中拿到CA的公钥进行解密,还有签名验证是否防篡改这点,自己纠结了很久,想着万一中间人(黑客)拿到CA的公钥呢,然后不照样可以伪造吗?
其实这一点我觉得是这样的,
1,首先植入到系统或浏览器的CA根证书是不会植入到第三方劫持软件(比如黑客用的)的,即使黑客有很大的本事拿到CA的公钥进行解密篡改啥的,如果返回给客户端,
这里第三方如果想跟客户端保持好https联系,那么客户端需要信任中间人的证书,如果出问题了,因为是用户自己的信任的,这么没有办法,出问题了用户自己担责。
2,假如中间人篡改了(其实我相信改不了),中间人不可能有CA的私钥,所以进行的加密,再返回给用户,用户用CA的公钥解密肯定是失败的。
通过以上两点自己思考的反证,足以证明,基于CA机构颁发的证书下的HTTPS是安全可靠的。
参考:
下面个人从阿里云上下载下来的证书和私钥,如下图所示:
nginx的nginx.conf中配置:
http{
...
include /etc/nginx/upstream.conf;
include /etc/nginx/conf.d/*.conf;
}
对接口服务api.***.vip来说,有两个配置文件,
一个是http(api-***.conf)的,其实仅是转发到了https上
一个是https(admin-***-ssl.conf)的,
1,下面是接口服务api.***.vip的ssl的配置
vi admin-***-ssl.conf 内容如下:
server {
listen 443 ssl;
server_name api.***.vip;
ssl_certificate /opt/xxx/3873053__***.pem;
ssl_certificate_key /opt/xxx/3873053__***.key;
#ssl_prefer_server_ciphers on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
#ssl_session_cache shared:SSL:50m;
ssl_session_timeout 5m;
add_header Strict-Transport-Security max-age=60;
access_log /var/log/nginx/access.log load-blance;
location / {
proxy_pass http://api_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
注:这个api_backend就是/etc/nginx/upstream.conf中的api_backend
文件中:
upstream api_backend {
server 192.168.*.1:8080;
server 192.168.*.2:8080;
}
这里放一下接口服务api.***.vip的http的配置:
vi api-***.conf 内容如下:
server {
listen 80;
server_name api.***.vip;
return 301 https://api.***.vip;
}
--------------------
2,下面是代理静态文件,冗余放下面总结使用,比如Vue打包编译后的静态文件
server {
listen 443 ssl;
server_name www.***.vip;
# 配置站点证书文件地址
ssl_certificate /***/3873053__***.pem;
# 配置证书私钥
ssl_certificate_key /***/3873053__***.key;
#ssl_prefer_server_ciphers on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
#ssl_session_cache shared:SSL:50m;
ssl_session_timeout 5m;
add_header Strict-Transport-Security max-age=60;
location / {
root /***/h5-vue;
#index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
关于Https不能被劫持,今天才明白为什么fiddler,Charles这些抓包其实就是“流量劫持工具”,也就解释了为什么用fiddler或者Charles抓https流量必须要安装自己颁发的证书了,具体的详情看下面这篇文章: