HTTPs原理

https核心目的是防止内容被篡改,核心方法是非对称加密

在http中,所有的信息都是明文传输,例如我要让服务器随机返回一个数字,整个过程如下:

如果有人想恶意篡改响应,就变成下面的流程了:

这种情况在以前很常见,很多时候你浏览一个网页时,页面中会塞满各种广告,但实际上服务提供商并没有加这些广告,而是网络运营商硬塞的,很恶心。有的时候也会非常不安全,因为可以使用这一方式制作钓鱼网站等。

所以,https的核心目的就是防止内容被篡改。一种较好的方式就是使用非对称加密。

服务器使用私钥加密内容后,客户端使用已知的公钥进行解密。在此过程中,黑客无法篡改内容,因为他没有服务器的私钥,无法加密篡改后的内容。

就好比你是一个攻击者,我告诉客户端一个随机字符串“sjdk”和一个公钥PubK,你拦截了该信息,并用这个公钥解密这个字符串得到数字5,但你不可能将这个数字5修改为8,因为你无法确定哪个字符串使用这个公钥PubK解密后能得到数字8。

但是,如果你连这个公钥都篡改了呢?譬如你拦截到信息后,使用自己的私钥生成数字8的加密字符串,并将这个字符串连同自己的公钥一同发给客户端。所以,这个问题就转换为如何保证公钥不会被篡改的问题。

如何保证服务器的公钥不会被篡改呢?

我不找服务器要它的公钥,而是找到一个可以信赖的第三方要这个公钥即可,这个第三方机构就是CA机构。

这样,即使黑客妄想篡改server返回的内容,他也无法篡改CA返回的私钥。

那么,如果他同时对两边进行篡改,即既修改server返回的内容,也修改CA返回的内容(server的公钥),可不可以呢?

理论上他无法修改CA的返回,因为CA返回server的公钥也是使用CA的私钥加密过的,客户端本地保存了CA的公钥,并且,这个公钥是随着操作系统安装一并保存的,或者由用户手动信任安装的,故可以认为CA的公钥是没有问题的,也就是可以认为CA返回的server公钥是没有被篡改过的。

由此可以说,你得到的server公钥没有被篡改,则使用该公钥解密的server的res内容也就不会被篡改了。

但实际情况和上面的流程还是有很大的区别的,但基本思路是一致的。server的公钥并不是由CA自己进行返回的,而是由server自己返回的,这是因为有了这种非对称加密的方式后,不论信息是由谁返回的,都可以保证信息是原始信息没有被其他服务器篡改过。所以一般的做法还是server从一开始就向CA申请一个证书,证书中会包含网站的信息(域名等)以及server的公钥,CA会使用自己的私钥来对该证书生成一个类似md5这种数字签名(注:只是对证书生成签名,里面的公钥仍然是明文,不会加密),然后返回给server保存起来,客户端申请和server建立https链接时,server就会将该证书返回,这里面也包括了CA生成的数字签名,客户端收到响应后使用本地已有的CA公钥来解密数字签名,然后使用同样的数字签名的方法对证书生成一个数字签名,对比自己生成的数字签名和CA公钥解密的数字签名就能判断这个证书是否真实有效,如果对不上或者本地没有这个CA的公钥,一些浏览器就会发出红色警告或者直接阻止用户访问以保护用户。

如果对上了,就使用证书里面的公钥加密要发给server的req,server就能通过它自己的私钥来解密这个信息。

这个过程中,就算黑客拦截了证书信息并妄想进行伪造,他也无法生成有效的证书签名

这里面的一个很大的问题就是,整个过程完全建立在对CA机构的信任上,如果CA机构被攻破,这个过程自然也就不安全了。其实任何CA机构(包括自建本地CA)的安全性都大差不差,之所以有些CA机构收费那么贵,其实本质上就是买了一份保险,保费越高,出了问题后的赔付也就越大。当然,还有一部分开销在于你向CA机构申请证书时,提供了一些信息(网站域名、主体等),越贵的CA机构对这个的审查就越严谨,这也是需要人工去完成的(便宜的或者免费的就不会用人工审查,而是使用 ACME 协议自动审查,例如使用DNS校验或者文件校验,Let’s Encrypt就是用的acme,总之,要验证这个域名确实是这个申请人的)

当然,这个加密和解密的过程其实相当复杂,对计算机来说也是一笔非常大的开销,所以https中并不会已知使用这种做法来传输信息,而是只有在建立https请求时,使用这种加密方式传输一个对称密钥,后续所有的内容都会直接使用这个对称密钥进行加密,这个过程就和http是一样的了。

注1:生成证书后一般会有三个文件(例如:Nginx反向代理wordpress开启HTTPS),它们的作用分别是:

  • xxx.crt: 证书文件,就算CA颁布给你的证书,最重要的就算它了
  • xxx.key: 你网站的公钥,客户端需要这个东西,它会和上面那个证书一同发给客户端
  • xxx.csr: 证书请求文件,你向CA申请证书时就需要给它这个文件,你需要提前使用自己是私钥以及网站信息生成好。相当于你要去办理业务时提交的材料。

注2:如果你看网上的一些生成本地CA证书的教程,会发现在生成证书签名时并没有使用到公钥,而是只用到了私钥

openssl req -new -key xxx_private.key -out localhost.csr

这是因为私钥中其实也是包含公钥的,所以csr中同样也是包含公钥的,这样一来证书签名就是完整的(同时签名了网站信息和server公钥)

注3:CA机构也是具有层级关系的,每个CA机构也是需要上层CA颁发的证书的。最顶层的root CA则会自己给自己颁发证书。

注4:有的时候还会看到 .pem 文件,它其实就算一种文件格式。例如一般也会将私钥保存为pem格式,你就可以将其命名为:xxx_private.key.pem。

如果将 .crt .key .csr 比作期刊要求的内容格式(标题怎么写、正文字体等),则pem就相当于文档格式,如 doc pdf 等

注5:很多时候可能会看到 challenge 这个单词,它的意思就是做审查用的,即CA验证域名是不是你的,可以使用dns验证或者文件验证等方式

参考:

如何让localhost具备https(本地自签名):https://www.section.io/engineering-education/how-to-get-ssl-https-for-localhost/

自建本地CA:https://blog.csdn.net/weixin_40228200/article/details/121895791

csr中有公钥信息吗:https://security.stackexchange.com/questions/111136/where-in-the-csr-is-the-public-key

Leave a Comment