HTTPS 扫盲记录

Jan 13, 2018 19:57 · 4237 words · 9 minute read HTTPS Security Web

最近在折腾 Headr 的域名时遇到了一些配置 HTTPS 的问题,所以研究了一下 HTTPS 的原理及一些基本概念,这篇把知识整理记录一下。也可以作为一个科普扫盲。

前置知识

虽然我主要想写的是 HTTPS 的原理,但是在讲原理之前有必要谈一些基础知识。不然没法讲明白 HTTPS。

HTTP

概念

HTTP(HyperText Transfer Protocol,超文本传输协议)是一个基于文本的应用层协议。使用浏览器访问网站时的应用层协议就是 HTTP。

所谓基于文本是说,区别于基于二进制,其协议内容是直接可读的文本,并且使用 \r\n 来分割。SIP 也是基于文本的协议。我写了一个最简单的 web 服务程序,通过浏览器来请求 http://localhost:8080 并使用 wireshark 抓包:

从图中我们可以看出这么几点:

  1. 如上所述,HTTP 是基于文本的。在图中我选中了那个 HTTP 请求,在下方就可以清楚地看到协议中的内容,HTTP header 中的各项字段例如 User AgentHost 等都是直接显示为文本并以 \r\n 作为分割;
  2. HTTP 协议是基于 TCP 协议的。所以在图中可以看到,一次 HTTP 请求之前,客户端(也就是浏览器)首先要和服务端(也就是我写的 hello world 程序)通过 TCP 的三次握手(图中前三条)建立连接,然后才是基于该连接发出 HTTP 请求;
  3. 一次 HTTP 请求后,建立的 TCP 连接就断开了。这点从图中最后的 TCP 断开连接四次握手就可以看出来。在这之后的下一次 HTTP 请求则需要重新建立 TCP 连接。但是其实我这里说得不是很准确,因为实际上在抓包时,断开 TCP 连接的请求并不是 HTTP 请求结束后马上就发出,而是过了一会才发出的。这就牵涉到我下面要说的长连接和短连接的概念了。

长连接和短连接

我们知道了 HTTP 协议是基于 TCP 的,但是 HTTP 是怎么使用 TCP 的呢?有两种方式:长连接(Keep-Alive)和短连接。刚刚我说“一次 HTTP 请求之后 TCP 连接会断开,下一次请求需要重新建立 TCP 连接”的时候你可能就意识到了,这不是很浪费时间和资源吗?是的。其实这就是所谓的短连接。而长连接,很容易想到,就是一次 TCP 连接并不会马上断开,而会持续(Keep-Alive)一段时间。想一想,现代网站上内容非常丰富,浏览器一次 HTTP 请求到一个 HTML 页面后,分析这个页面,发现其中有很多外部资源(图片啊,CSS啊,JS脚本啊),然后就又要去请求这些资源,才能加载完一个页面。如果每次请求都需要重新建立 TCP 连接,那开销就太大了。

在 HTTP 1.0 版本时,默认采用的是短连接。那时候 Web 才刚刚诞生,网页相对现在简单许多,所以短连接问题不大;而到了 95 年底开始制定 HTTP 1.1 草案时,网页已经开始变得很复杂了。所以 HTTP 1.1 就已经开始采用长连接(Keep-Alive)方式了。

HTTP 和 HTTPS

从上面的抓包图我们也可以看见,HTTP 协议中的内容是明文传输的。当传输的内容中有隐私信息时,这就很不安全。于是网景公司设计了 SSL(Secure Sockets Layer)协议用于对 HTTP 协议传输的数据进行加密,从而就诞生了HTTPS(HyperText Transfer Protocol over Secure Socket Layer)协议。

SSL/TLS

SSL(Secure Sockets Layer,安全套接层),如上所述,是网景公司设计开发来用于加密 HTTP 协议的协议。到了1999年,SSL 因为应用广泛,已经成为互联网上的事实标准。IETF 就在那年把 SSL 标准化。标准化之后的名称改为 TLS(Transport Layer Security),中文叫做“传输层安全协议”。很多相关的文章都把这两者并列称呼(SSL/TLS),因为这两者可以视作同一个东西的不同阶段。

HTTPS

HTTPS 其实就可以理解为 HTTP + SSL/TLS。即 HTTP 下加入 SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL,用于安全的 HTTP 数据传输。

对称加密和非对称加密

所谓加密,就是把明文变成密文;所谓解密,就是把密文还原成明文。在这两个过程中,都需要一个密钥来参与运算。这个”钥“字可以说非常形象了:加密就是给一个东西上锁,我们需要一把钥匙来把锁锁上;解密反之,需要一把钥匙来把锁打开。那么什么是对称加密什么是非对称加密呢?

简单来说,对称加密,就是加/解密使用同一把钥匙。比如你在百度云上放了一堆学习资料,并给他们加了个密码。别人要访问你的学习资料时,就需要用这个密码来解锁你的学习资料内容。

而非对称加密,就是加/解密使用不同的钥匙。讲这个可以写一本书了,我就不在这里详细地介绍了。只做一些扫盲。非对称加密需要一对公私钥。公钥可以解密用私钥加密的内容,私钥也可以解密公钥加密的内容。两个密钥都不能自己解密自己加密的内容,所以它们总是成对存在。而所谓“公私”是说公钥是可以公开的,随便什么人都可以获得你的公钥;而私钥是不能给别人看的,必须妥善保存。

两种加密技术的特点在于,非对称加密的保密性更好,能干的事情比对称加密要多。然而非对称加密由于涉及到复杂的数学运算问题,性能要劣于对称加密。

常见的对称加密算法:AES,RC4,3DES;

常见的非对称加密算法:RSA,DSA/DSS。

HASH 算法和数字签名

HASH 算法

HASH 算法又称摘要算法,散列算法,目的是将任意长度的信息转换为较短的固定长度的值,通常其长度要比被 HASH 的信息小得多,HASH 算法不可逆,即不能(准确地说是非常非常难)从 HASH 值反算出原信息。而且,对原始数据做一个 bit 的修改,都会导致计算出的 HASH 值完全不同。常见的 HASH 算法如有 MD5,SHA-1, SHA-256 等。

数字签名

签名就是在信息的后面再加上一段内容(信息经过 HASH 后的值),可以证明信息没有被修改过。HASH 值一般都会加密后(也就是签名)再和信息一起发送,以保证这个 HASH 值不被修改。

CA 和证书

程序员介绍信

为了讲明白这个问题,我先举个例子。

假设公司 A 要派一个程序员甲去公司 B 干活,但是 B 公司没有一个人认识程序员甲。那程序员甲到了 B 公司,他怎么向 B 公司的前台小姐证明“我是我”呢?

他可以带一封介绍信。这封信由 A 公司的 CEO 所写,“兹有程序员甲一名,前往贵公司写代码,请给予接待”云云,然后盖上 A 公司的公章。那么程序员甲带着这封信到了 B 公司,把介绍信交给前台小姐。由于 A,B 公司有业务往来,前台小姐认得 A 公司的公章,那么她就可以相信程序员甲是程序员甲了。

(当然这里假设 A 公司的公章无法被伪造)

然而问题来了。现在有 CDE… 公司都要派各自的程序员乙丙丁… 去 B 公司干活,前台小姐认各个公司的公章认疯了。又怎么办呢?

于是出现了一个 X 公司看到了这个商机,它就开了一个“代理公章”的服务。内容如下:

X 公司受所有公司信任。当 A 公司的程序员甲要去 B 公司时,他需要带两封信:

  1. X 公司的介绍信,信中说明 A 公司受 X 公司信任,并带有 X 公司的公章;
  2. A 公司的介绍信,同前所述。

这样做就为 B 公司的前台小姐解决了问题。她不再需要去认各家公司的公章,她只需要认得 X 公司的公章就行了。这里就存在一个信任链:B 公司 -> X 公司 -> A 公司。

Certificate Authority

CA(Certificate Authority)其实就是一个 X 公司这样的为各家网站颁发证书的权威机构。CA 证书,就是 CA 机构颁发的证书。CA 证书在 HTTPS 中的作用就是,被服务器用来向客户端证明“我是我”(而不是一个中间黑客)。这一步很关键,也是为什么你在浏览一些网站时会收到浏览器的提示”不安全的证书“。其实就是说服务器发给你的证书是不受浏览器信任的。

那么浏览器是怎么判断这个证书是不是受信任的呢?

这就是通过刚刚说的信任链了。你的电脑上本身是有一些受信任的证书的。浏览器会把服务器提供的 CA 证书拿来和电脑上的证书作比对,如果这个证书被一个受信任的证书所信任,那么这个证书就是可信任的。(这是简单地说,具体的判断还要包括证书是否过期了,证书上绑定的域名是否和实际访问的域名一致等条件)

而本机上的证书,其实构成了如下的一个信任树:

C 证书信任 A,B 证书,A,B 又分别信任 A1 和 A2,B1 和 B2。那么 A1 就可以通过信任链 A1 -> A -> C -> B -> B1 来信任 B1 了。而处于顶上的 C 证书,就是所谓的“根证书”。除了根证书,其他所有证书都要依靠上一级来证明自己。而根证书是不需要被证明本身可靠的。

根证书是这里整个安全体系的根本,如果根证书不被信任了,所有证书也都不可信了。后果将是灾难性的。

HTTPS 原理

终于讲完了基础知识,现在来分析一下 HTTPS 的原理。

与 HTTP 简单粗暴的建立完 TCP 连接就开始发请求不同,HTTPS 开始时多了很多认证和加解密的过程。过程描述如下:

  1. 客户端发起一个 HTTPS 的请求,将自己的一套加密规则(专业点叫 Cipher Suite,密钥算法套件)发送给服务端;
  2. 服务端收到套件后,首先与自身支持的密钥算法比对,如果不支持客户端发来的密钥套件则断开;如果支持,服务端则会从中选出一种(非对称)加密算法以及一个 HASH 算法,包含在一个证书中返回给客户端。证书中还包含了一个公钥,颁证机构,网址,有效日期等等;
  3. 客户端收到证书后,首先按前面所描述的过程验证证书的合法性。如果证书验证合法失败,则断开(或者提示用户不受信任的证书,这个取决于客户端了);如果验证通过(或者用户选择了接受不受信任的证书),客户端就会 (a) 生成一个随机密码,并用服务端发来的公钥对随机密码进行加密。(b) 用约定好的 HASH 算法 HASH 一个握手消息得到其数字签名,并用生成的随机密码对“握手消息 + 握手消息数字签名”进行加密。© 把被公钥加密的随机密码被随机密码加密的“握手消息 + 握手消息数字签名”全部发给服务端;
  4. 服务端收到这些消息后,首先用自己的私钥解密出被公钥加密了的随机密码,然后用随机密码解密出收到的“握手消息 + 握手消息数字签名”。然后服务端使用相同的 HASH 算法 HASH 收到的握手消息,并将其与收到的握手消息数字签名相比对,如果一致说明握手消息没有被修改;
  5. 服务端用收到随机密码加密握手消息回复及其数字签名,并发回给客户端;
  6. 客户端收到回复,用随机密码解密,验证签名。如果一致,则握手结束。之后的所有通信都使用同样的随机密码进行加解密。

这里浏览器与网站互相发送加密的握手消息并验证,目的是为了保证双方都获得了一致的密码,并且可以正常的加密解密数据,为后续真正数据的传输做一次测试(即握手的意义)。

可以看到,客户端生成的随机密码(一种对称加密)是之后通信保密的关键,所以最开始使用了非对称加密(公私钥)来进行加密交换。

而 HASH 算法是为了保证数据在传输过程中的完整性(Integrity)。

综上就是 HTTPS 的连接建立过程。

总结

HTTPS 非常安全,所以各大互联网公司(Google,Facebook,Apple…)都在推行 HTTPS。以后的互联网肯定会被 HTTPS 所充斥。但是要注意的是 HTTPS 不是来替代 HTTP 的,只不过是给 HTTP 加了密。

这篇文章本质上讲还是一篇扫盲科普性质的文章,目的是让你以后跟人聊起 HTTPS 不至于什么都不知道。但是文章中提到的很多知识都可以专门另开一门学科,有兴趣之后可以再深入研究。

Reference

https://zhuanlan.zhihu.com/p/27395037

http://www.cnblogs.com/zery/p/5164795.html

https://kb.cnblogs.com/page/194742/

http://www.techug.com/post/https-ssl-tls.html

https://www.guokr.com/post/114121/