HTTPS 基础知识(密钥、对称加密、非对称加密、数字签名、数字证书)

2023-02-12,,,,

    HTTPS 概述
    对称加密
    非对称加密
    非对称加密改良方案
    非对称加密 + 对称加密
    中间人攻击
    数字证书
    数字签名
    HTTPS 工作原理

HTTPS 概述

HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer 或 Hypertext Transfer Protocol Secure,超文本传输安全协议),是以安全为目标的 HTTP 通道,简单讲是 HTTP 的安全版。即 HTTP 下加入 SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。 它是一个 URI scheme(抽象标识符体系),句法类同 http: 体系。用于安全的 HTTP 数据传输。https: URL 表明它使用了 HTTP,但 HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP 与 TCP 之间)。

WEB 服务存在 http 和 https 两种通信方式,http 传输不加密,默认采用 80 作为通讯端口;https 对传输的数据进行加密,默认采用 443 端口。目前主流的网站基本上开始默认采用 HTTPS 作为通信方式。

SSL/TLS 是一个密码学协议,它的目标并不仅仅是网页内容的加密传输。SSL/TLS 的主要目标有四个:加密安全、互操作性、可扩展性和效率。对于安全性的保障,它还会从多个方面进行,包括机密性,真实性以及完整性。机密性是指,传输的内容不被除通信的双方外的第三方获取;真实性是指,通信的对端正是期待的对端,而不是其它第三方冒充的;完整性则是指,传输的数据是完整的,数据没有被篡改或丢失。为了平衡多种需求,SSL/TLS被设计为一个安全框架,其中可以应用多种不同的安全方案,每种方案都由多个复杂的密码学过程组成。不同的安全方案,在安全性和效率之间有着不同的取舍,并由不同的密码学过程组成。

对称加密

对称加密算法的加密和解密都是用同一个密钥

如果通信双方都各自持有同一个密钥,且没有别人知道,则两方的通信安全是可以被保证的(除非密钥被破解)。然而,最大的问题就是这个密钥怎么让传输的双方知晓,同时不被别人知道。如果由服务器生成一个密钥并传输给浏览器,这个传输过程中密钥被别人劫持,之后他就能用密钥解开双方传输的任何内容。

如果浏览器内部预存了网站 A 的密钥,且可以确保除了浏览器和网站 A,不会有任何外人知道该密钥,那理论上用对称加密是可以的。这样,浏览器只要预存好世界上所有 HTTPS 网站的密钥就可以了。显然,这样做是不现实的。

怎么办?解决这个问题,我们就需要非对称加密。

非对称加密

基于对称加密存在的问题,又有了非对称加密。非对称加密算法需要一组密钥对,分别是公钥和私钥,这两个密钥是成对出现的。公钥加密的内容需要对应的私钥解密,私钥加密的内容需要对应的公钥解密。私钥由服务器自己保存,公钥发送给客户端。客户端拿到公钥后可以对请求进行加密后发送给服务端,这时候就算中间被截获,没有私钥也无法解密发送的内容,这样确保了客户端发送到服务端数据的安全。

非对称加密改良方案

通过一组公钥私钥,已经可以保证单个方向传输的安全性,那用两组公钥私钥,是不是就能保证双向传输都安全了?请看下面的过程:

    某网站拥有用于非对称加密的公钥 A1、私钥 A2;浏览器拥有用于非对称加密的公钥 B1、私钥 B2。
    浏览器向网站服务器请求,服务器把公钥 A1 明文传输给浏览器。
    浏览器把公钥 B1 明文传输给服务器。
    之后浏览器向服务器传输的所有东西都用公钥A1加密,服务器收到后用私钥 A2 解密。由于只有服务器拥有私钥 A2 进行解密,所以能保证这条数据的安全。
    服务器向浏览器传输的所有东西都用公钥 B1 加密,浏览器收到后用私钥 B2 解密。同上也可以保证这条数据的安全。

可见确实可行。抛开这里面仍有的漏洞不谈(中间人攻击,下文会讲),HTTPS 的加密却没使用这种方案,为什么?最主要的原因是非对称加密算法非常耗时,特别是加密解密一些较大数据的时候有些力不从心。而对称加密快很多。那我们能不能运用非对称加密的特性解决前面提到的对称加密的问题?

非对称加密 + 对称加密

既然非对称加密耗时,我们考虑是否可以采用非对称加密+对称加密结合的方式,而且要尽量减少非对称加密的次数。

非对称加密、解密各只需一次的方法:

    某网站拥有用于非对称加密的公钥 A1、私钥 A2。
    浏览器向网站服务器请求,服务器把公钥 A1 明文给传输浏览器。
    浏览器随机生成一个用于对称加密的密钥 X,用公钥 A1 加密后传给服务器。
    服务器拿到后用私钥 A2 解密得到密钥 X。
    这样双方就都拥有密钥 X 了,且别人无法知道它。之后双方所有数据都用密钥 X 加密解密即可。

HTTPS 基本就是采用了这种方案。但还是有漏洞的。

中间人攻击

中间人的确无法得到浏览器生成的对称密钥 X,这个密钥本身被公钥 A1 加密,只有服务器才能用私钥 A2 进行解密。然而中间人却完全不需要拿到私钥 A2 就能劫持信息,请看:

    某网站拥有用于非对称加密的公钥 A1、私钥 A2。
    浏览器向网站服务器请求,服务器把公钥 A1 明文传输给浏览器。
    中间人劫持到公钥 A1,保存下来,把数据包中的公钥 A1 替换成自己伪造的公钥 B1(它当然也拥有公钥 B1 对应的私钥 B2)。
    浏览器随机生成一个用于对称加密的密钥 X,用公钥 B1(浏览器不知道公钥被替换了)加密后传给服务器。
    中间人劫持后用私钥 B2 解密得到密钥 X,再用公钥 A1 加密后传给服务器。
    服务器拿到后用私钥 A2 解密得到密钥 X。

这样在双方都不会发现异常的情况下,中间人得到了对称密钥 X。根本原因是浏览器无法确认自己收到的公钥是不是网站自己的。那么下一步就是解决这个问题:如何证明浏览器收到的公钥一定是该网站的公钥?

这就好比是,骗子在同学参加四、六级考试的时候,给同学的家长打电话或发短信,声称自己是学校的辅导员,并表示同学病重急需用钱,要求家长汇钱,同学家长汇钱给骗子而遭受巨大损失的情况。这就是数据/信息真实性没有得到足够验证而产生的问题。

再比如,一个仿冒的 taobao 网站,域名与真实的网站非常相似。我们一不小心输错了域名,或域名被劫持而访问了这个仿冒的网站,然后像平常在 taobao 购物一样,选择宝贝,并付款,但最后却怎么也收不到货物。

数字证书

现实生活中,如果想证明某身份证号一定是小明的,怎么办?看身份证。这里政府机构起到了“公信”的作用,身份证是由它颁发的,它本身的权威可以对一个人的身份信息作出证明。互联网中也有这么一个公信机构,CA 机构。

网站在使用 HTTPS 前,需要向“CA机构”申请颁发一数字证书,数字证书里有证书持有者、证书持有者的公钥等信息,类似如下(实际上就是一堆数据,这里为了直观)。服务器把证书传输给浏览器,浏览器从证书里取公钥就可以了。然而这里又有一个显而易见的问题:证书本身的传输过程中,如何防止被篡改?即如何证明证书本身的真实性?数字证书怎么防伪呢?

CA 机构就是数字证书颁发的权威机构,负责颁发证书以及验证证书的合法性。如果服务器需要做个有身份的服务器,就需要向 CA 机构提交申请,当然有钱才好办事,交钱才能给你办证……

服务器向 CA 机构提交申请,需要提交站点的信息如域名、公司名称、公钥等等,CA 审批无误之后就可以给服务器颁发证书了!

客户端在拿到服务器的证书后,就需要验证证书编号是否能在对应的 CA 机构查到,并且核对证书的基本信息如证书上的域名是否与当前访问的域名一致等等,还可以拿到证书中服务器的公钥信息用于协商对称密钥!

证书颁发了,可是又怎么防止伪造,怎么保证在传输过程中不被篡改呢?即如何证明证书本身的真实性?数字证书怎么防伪呢?

数字签名

我们把证书内容生成一份“签名”,比对证书内容和签名是否一致就能察觉是否被篡改。这种技术就叫数字签名。

数字签名的制作过程:

    CA 拥有非对称加密的私钥和公钥。
    CA 对证书明文信息进行 hash。
    对 hash 后的值用私钥加密,得到数字签名。

明文和数字签名共同组成了数字证书,这样一份数字证书就可以颁发给网站了。那浏览器拿到服务器传来的数字证书后,如何验证它是不是真的?(有没有被篡改、掉包)

下图中左侧是数字签名的制作过程,右侧是验证过程

浏览器验证过程:

    拿到证书,得到明文 T1,数字签名 S1。
    用 CA 机构的公钥对 S1 解密(由于是浏览器信任的机构,所以浏览器保有它的公钥。详情见下文),得到 S2。
    用证书里说明的 hash 算法对明文 T1 进行 hash 得到 T2。
    比较 S2 是否等于 T2,等于则表明证书可信。

下图直观展示了如何给证书加数字签名!也就是 CA 给服务器颁发的证书进行盖章。

那浏览器拿到服务器传来的数字证书后,如何验证它是不是真的?(有没有被篡改、掉包)下图直观展示了如何验证证书的真伪

为什么使用签名可以证明证书可信?
假设中间人篡改了证书的原文,由于他没有 CA 机构的私钥,所以无法得到此时加密后签名,无法相应地篡改签名。浏览器收到该证书后会发现原文和签名解密后的值不一致,则说明证书已被篡改,证书不可信,从而终止向服务器传输信息,防止信息泄露给中间人。

既然不可能篡改,那如果整个证书被掉包呢?

假设有另一个网站 B 也拿到了CA 机构认证的证书,它想搞垮网站 A,想劫持网站 A 的信息。于是它成为中间人拦截到了 A 传给浏览器的证书,然后替换成自己的证书,传给浏览器,之后浏览器就会错误地拿到 B 的证书里的公钥了,会导致上文提到的漏洞。

其实这并不会发生,因为证书里包含了网站 A 的信息,包括域名,浏览器把证书里的域名与自己请求的域名比对一下就知道有没有被掉包了。

客户端发起requests请求中的verify参数就是用于验证服务端证书的证书,可以理解为根证书。如果verify=False,表示客户端不校验服务端的证书。

requests.get(base_url, params=params, verify=False)

不校验服务端证书存在服务端证书被替换的风险,存在中间人攻击的风险。

制作数字签名时为什么需要 hash 一次?
最显然的是性能问题,前面我们已经说了非对称加密效率较差,证书信息一般较长,比较耗时。而 hash 后得到的是固定长度的信息(比如用 md5 算法 hash 后可以得到固定的 128 位的值),这样加密解密就会快很多。当然除此之外也有安全上的原因。

HTTPS 必须在每次请求中都要先在 SSL/TLS 层进行握手传输密钥吗?
显然每次请求都经历一次密钥传输过程非常耗时,那怎么达到只传输一次呢?用session就可以。

服务器会为每个浏览器(或客户端软件)维护一个 session ID,在 TSL 握手阶段传给浏览器,浏览器生成好密钥传给服务器后,服务器会把该密钥存到相应的 session ID 下,之后浏览器每次请求都会携带 session ID,服务器会根据 session ID 找到相应的密钥并进行解密加密操作,这样就不必要每次重新制作、传输密钥了

最后补充一下CA机构的知识,以及如何查看自己浏览器上的 CA证书

哪些 CA 机构对于客户端来说是权威或者说是认可的呢?以 chrome 为例查看下客户端内置的 CA 机构的信息,包含了 CA 的公钥、签名算法、有效期等等…在 chrome 中,更多工具->开发者选项->Security->View certificate,就可以查看证书的相关信息了。

HTTPS 工作原理

本文要讲的是 HTTPS,但是到目前为止 HTTPS 尚未讲解!其实 HTTPS=HTTP+SSL,在 HTTP 层和 TCP 之间加了一个 SSL/TLS 层,如下图:

SSL(Secure Sockets Layer)中文叫“安全套接层”,后来由于广泛应用,SSL 标准化之后就改名为 TLS(Transport Layer Security)了,其实 HTTPS 就是通过上面说到的那些手段来解决网络上可能存在的数据泄密、篡改、假冒的这些问题,保证网络传输的安全的啦!

使用 HTTPS 访问服务器的过程如下:

    client 向 server 发送请求 https://baidu.com,然后连接到 server 的 443 端口。

    服务端必须要有一套数字证书,可以自己制作,也可以向组织申请。区别就是自己颁发的证书需要客户端验证通过,才可以继续访问,而使用受信任的公司申请的证书则不会弹出提示页面,这套证书其实就是一对公钥和私钥。

    传送证书
    这个证书其实就是公钥,只是包含了很多信息,如证书的颁发机构,过期时间、服务端的公钥,第三方证书认证机构(CA)的签名,服务端的域名信息等内容。

    客户端解析证书
    这部分工作是由客户端的 TLS 来完成的,首先会验证公钥是否有效,比如颁发机构,过期时间等等,如果发现异常,则会弹出一个警告框,提示证书存在问题。如果证书没有问题,那么就生成一个随机值(密钥)。然后用证书对该随机值进行加密。

    传送加密信息
    这部分传送的是用证书加密后的密钥(随机值),目的就是让服务端得到这个密钥(随机值),以后客户端和服务端的通信就可以通过这个随机值来进行加密解密了。

    服务端加密信息
    服务端用私钥解密,得到了客户端传过来的密钥(随机值),然后把内容通过该值进行对称加密。

    传输加密后的信息
    这部分信息是服务端用密钥(随机值)对称加密后的信息,可以在客户端被还原。

    客户端解密信息
    客户端用之前生成的密钥(随机值)解密服务端传过来的信息,于是获取了解密后的内容。

HTTPS 基础知识(密钥、对称加密、非对称加密、数字签名、数字证书)的相关教程结束。

《HTTPS 基础知识(密钥、对称加密、非对称加密、数字签名、数字证书).doc》

下载本文的Word格式文档,以方便收藏与打印。