HTTP 是Hyper Text Transfer Protocol(超文本传输协议)的缩写。HTTP 协议位于 TCP/IP 协议栈的应用层。

一、HTTP 协议介绍

1.1 什么是 HTTP

HTTP 是一个客户端和服务器端请求和应答的标准,主要用于从万维网(即WWW,全称 World Wide Web)服务器传输超文本到本地浏览器之间的请求数据和响应数据的协议。客户端通过使用网页浏览器或者其它的工具发起一个 HTTP 请求到服务器上指定端口(默认端口为80),服务器在收到请求之后,返回响应内容(文本、图片等)。

HTTP 协议是基于 TCP 协议来进行数据传输的。

1.2 HTTP 的版本

HTTP 协议已经演化出了很多版本,它们中的大部分都是向下兼容的。客户端在请求的开始告诉服务器它采用的协议版本号,而后者则在响应中采用相同或者更早的协议版本。现在大多使用的都是1.1版本。

  • 1.0 版本: HTTP 协议非常老的标准,为了提高系统的效率,HTTP 1.0 规定浏览器与服务器只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个 TCP 连接,服务器完成请求处理后立即断开 TCP 连接,服务器不跟踪每个客户也不记录过去的请求。正式因为这种特性造成了一些性能上的缺陷。

  • 1.1 版本: 克服了 HTTP 1.0 的缺陷,HTTP 1.1 支持持久连接(HTTP/1.1 的默认模式使用带流水线的持久连接),在一个 TCP 连接上可以传送多个 HTTP 请求和响应,减少了建立和关闭连接的消耗和延迟。同时还增加更多的请求头和响应头来改进和扩充 HTTP 1.0 的功能(如 POST 请求头字段等)。

  • 2.0 版本: 2015 年 5 月作为互联网标准正式发布。主要新增如下特性:多路复用,二进制分帧,首部压缩,服务端推送。

二、HTTP 消息请求

2.1 URI、URL、URN

通过 HTTP 或者 HTTPS 协议请求的资源由统一资源标识符(Uniform Resource IdentifiersURI)来标识。我们常用的是 URL,那么 URI, URL, URN 之前有什么区别和联系了?

1
2
3
URI = Uniform Resource Identifier 统一资源标识符
URL = Uniform Resource Locator 统一资源定位符
URN = Universal Resource Name 统一资源名称

三者关系如下图:

URI用来唯一标识符来标识一个资源,是一个通用的概念,URIURLURN两个子集组成。

URL通过描述资源的位置来标识资源。

URN通过资源的名字来标识资源,与其所处的位置无关,这样即使资源的位置发生变动,其URN也不会变化。

HTTP 规范将更通用的概念 URI 作为其资源标识符,但是实际上,HTTP 应用程序处理的只是 URI 的 URL 子集.

2.2 消息请求格式

2.3 HTTP 常见的请求方法

HTTP 消息请求的第一个字段就是“请求方法”,HTTP 1.1 中定义的几种常见的请求方法如下(只列出了常用的):

  • GET
    向服务器获取数据。使用 GET 请求方法时,消息 Body 中没有“请求数据”(见上面消息格式的图)部分,所以将需要提交到服务器的数据放在 URL 中,因此能够提交到服务器的数据会受到 URL 长度的限制。
1
2
3
4
5
6
7
8
9
10
 各个浏览器对URL长度的限制如下(这些限制值可能随着浏览器的版本的更新而发生改变,仅供参考):
1. IE浏览器(Microsoft Internet Explorer) 对URL长度限制是2083(2K+53),超过这个限制,则自动截断(若是form提交则提交按钮不起作用)。
2. Firefox
Firefox(火狐浏览器)对URL长度限制是65536字符,但实际上有效的URL最大长度不少于100,000个字符。
3. Chrome
chrome对URL长度限制是8182个字符。
4. Safari
Safari对URL长度限制是80000字符。
5. Opera
Opera浏览器对URL长度限制是190000 字符。
  • POST
    向服务器提交数据(例如提交表单或者上传文件)。提交的数据包含在 Body 中。

三、HTTP 消息响应

3.1 消息响应格式

3.2 HTTP 状态码

状态代码由三位数字组成,第一个数字定义了响应的类别,共分五种类别:

1
2
3
4
5
1xx消息—— 请求已被服务器接收,继续处理
2xx成功 —— 请求已成功被服务器接收、理解、并接受
3xx重定向 —— 需要后续操作才能完成这一请求
4xx请求错误 —— 请求含有词法错误或者无法被执行
5xx服务器错误 —— 服务器在处理某个正确请求时发生错误

常见的状态码有:

1
2
3
4
5
6
7
200 OK                        //客户端请求成功
400 Bad Request //客户端请求有语法错误,不能被服务器所理解
401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden //服务器收到请求,但是拒绝提供服务
404 Not Found //请求资源不存在,比如:输入了错误的URL
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable //由于超载或系统维护,服务器暂时的无法处理客户端的请求

关于 HTTP 状态码的完整定义见:https://tools.ietf.org/html/rfc2616#page-39

四、HTTPS 之密码学基础

4.1 对称加密算法

对称加密算法(英文:Symmetric-key algorithm)是指密码学中的一类加密算法,又称为:私钥加密、共享密钥加密。这类算法在加密和解密时使用相同的密钥(或者这 2 个密钥可以通过简单的规则相互推算)。
“对称加密算法”比“非对称加密算法”速度更快,但对称加密算法的主要缺点在于要求加密和解密的双方获取相同的密钥,这样只要密钥被泄漏,则密文将不再安全。

常见的对称加密算法有:

  • DES: Data Encryption Standard, 数据加密标准,速度较快,适用于加密大量数据的场合。
  • 3DES: Triple DES, 是基于 DES,对一块数据用三个不同的密钥进行三次加密,强度更高。
  • AES: Advanced Encryption Standard, 高级加密标准,是下一代的加密算法标准,速度快,安全级别高。
  • Blowfish: 一个 64 位分组及可变密钥长度的对称密钥分组密码算法,可用来加密 64 比特长度的字符串。
  • IDEA: 在 DES 算法的基础上发展出来的,密钥为 128 位。
  • RC5
  • RC6

4.2 非对称加密算法

“非对称加密算法”又称为“公开密钥加密”(英语:public-key cryptography)。也一种密码学算法类型,在这类加密算法中,需要一个“密钥对”,即“私钥”和“公钥”。这两个密钥是数学相关,用某个密钥对的“私钥”加密的信息,只能用该密钥对的“公钥”才能解密。同样,用“公钥”加密的信息,也只能用该密钥对的“私钥”才能解密。

“私钥”一般都是自己保留,不透露给他人;而“公钥”可以公开给他人。

“非对称加密算法”比“对称加密算法”安全性更高,不用担心加密密钥的泄漏,因为“公钥”是公开的,不存在泄漏。但“私钥”还是要保存妥当,不能泄露给他人,因为我们不需要在网络上传输“私钥”,所以“私钥”泄露的可能性会小很多。

但是“非对称加密算法”比“对称加密算法”的运算速度慢很多,一般在数据量比较少的时候采用“非对称加密算法”。

如上图,因为李四的“公钥”是公开的,所以张三要给李四发送信息,可以使用李四的“公钥”来加密信息。李四收到密文信息之后就可以使用自己的“私钥”来解密信息。因为其他人没有李四的“私钥”,所以就算密文信息被他人截获也无法解密。

常见的非对称加密算法有:

  • RSA: 由 RSA 公司发明,是一个支持变长密钥的公共密钥算法,需要加密的文件块的长度也是可变的。
  • DSA: Digital Signature Algorithm, 数字签名算法,是一种标准的 DSS(数字签名标准)。
  • ECC: Elliptic Curves Cryptography, 椭圆曲线密码编码学。

非对称算法虽然安全,但运算速度很慢,而对称算法的速度虽快,但在管理和传输密钥方面会存在安全隐患。在实际的操作过程中,我们通常采用的方式是:采用“非对称加密算法”管理“对称加密算法”的密钥,然后用“对称加密算法”加密数据,这样我们就集成了两类加密算法的优点,既实现了加密速度快的优点,又实现了安全方便管理密钥的优点。

使用 OpenSSL 生成 RSA 公私钥对

1
2
3
4
5
// 生成1024位的私钥
openssl genrsa -out d:\rsa_private.pem 1024

// 生成私钥对应的公钥
openssl rsa -in d:\rsa_private.pem -pubout -out d:\ca_public.pem

git 客户端安装文件中的提供的ssh-keygen.exe工具也可以用来生产非对称加密的公私钥对。

4.3 散列函数

散列函数(英文:Hash Function)是将任意长度的的输入转化为定长输出的算法。编程中对散列函数使用非常普遍,如MD5,但并不是所有的散列函数都适用于密码学。密码学的散列函数必须同时具有如下几个额外的特性:

  • 单向性:给定一个散列值,无法反向找到或者构造出生成它的消息。
  • 抗碰撞性:给定一个消息和它的散列值,无法找到具有相同散列值的不同的消息。

散列函数最常用的场合是以紧凑的方式来唯一表示大量数据,如“数字签名”中用到散列函数生成摘要信息等。

常见的散列函数:

  • MD5:1991 年对 MD4 的改进版本,该算法不可逆。2004 年王小云等人证明了完全碰撞,在理论上说明 MD5 可以被完全攻破,2005 年,Lenstra 等人证明了现实中的碰撞,展示了两张完全不同的证书却拥有同样的 MD5 散列值。所以,目前MD5已经不安全了。
  • SHA-1:SHA-1 在许多安全协议中广为使用,包括 TLS 和 SSL、PGP、SSH、S/MIME 和 IPsec,曾被视为是 MD5 的后继者,但因为在理论在已经证明 SHA1 可以被破解,但限制于计算机的计算能力所以 SHA-1 被破解还是很困难,所以 SHA-1 的安全性如今被密码学家严重质疑。
  • SHA-256:SHA-224、SHA-256、SHA-384、SHA-512 一起并称为 SHA-2,至今尚找出对 SHA-2 有效的破解方法。

五、数字签名与数字证书

5.1 数字签名

数字签名(英文:Digital Signature)类似于我们写在纸上的手写签名,它的诞生主要是为了解决如下问题:

  1. 证明该文件(或信息)是由你发送的。
  2. 证明该文件(或信息)没有被他人篡改过。

其实,我们生活中手写签名的纸质合同也是通过各种形式达到上面 2 个效果(如:合同一式多份,每份合同都有双方签名等)。

数字签名利用了“非对称加密算法”,签名和验证签名的过程如下图(图中的“认证”部分不是数字签名必须的,在“数字证书”部分会介绍):

假设“李四”要发送一份数据给“张三”:
发送者“李四”对数据生成摘要信息(摘要明文A),然后使用“李四”的“私钥”加密摘要信息;接收者“张三”收到加密的摘要信息之后:

  1. 使用“李四”的“公钥”对加密的摘要信息进行解密。若能解密则证明签名是由“李四”所签,这是因为只有“李四”的“私钥”加密的数据才能由“李四”的“公钥”解密,而又只有“李四”才有“李四”的“私钥”

  2. 并将数据使用相同的摘要算法自己也生成一份摘要信息(摘要明文B),然后比较 A 和 B。若两者相等,则证明了该数据内容没有被他人篡改过。

通过上面的过程我们可以知道:

  1. 数字签名具有合法性的前提条件是用于加密散列值的“私钥”没有被泄露。
  2. 数字签名不负责数据的加密,若要防止数据被他人窥视,则还要结合其他手段,如使用接收者的“公钥”对数据进行加密等。

如何获取签名者的公钥?如何保证获得的公钥就是签名者的,而不是他人的?基于这些问题,数字签名需要结合后面介绍的数字证书来使用(也就是上图中的“认证”文件)。

5.2 数字证书

有了上面的公开密钥算法(也就是“非对称加密算法”)之后,我们就可以通过他人的公开密钥(公钥)与其安全通信了,但是还有一些悬而未决的问题:

  • 如何获取那些从未谋面的人的公钥?
  • 如何存储和吊销这些公钥?
  • 如何确保获取的公钥就是那个人的?

公钥基础设施(public key infrastructure, 简称KPI)就是为了解决这个问题而建立的。PKI的目标就是为了实现不同成员在不见面的情况下进行安全通信的,我们当前采用的 PKI 模型是基于可信的第三方机构,也就是“证书颁发机构”(certification authority,简称CA)签发的证书。证书中存储了使用“证书颁发机构”的私钥加密之后的申请者的公钥信息。

5.2.1 数字证书的申请

数字证书需要向“证书颁发机构”提交申请,并通过审核之后才能颁发。因为数字证书中存储的是申请者的公钥,所以如果申请者的私钥丢失或泄漏,就需要向“证书颁发机构”申请注销该证书。

Web服务器CA申请证书的流程大致如图:

“证书”中主要包含了经过“证书颁发机构”的私钥加密过后的申请者的“公钥”“证书有效期”“申请者信息(如域名等)”。更详细的信息,可以参考《HTTPS 权威指南》第 3.3.1 章节。

5.2.2 数字证书的验证

以“Chrome 浏览器”为例:
浏览器会内置各大著名的“证书颁发机构”的“公钥”,当收到 Web 服务器返回的“服务器证书”后,Chrome 会尝试使用内置的该“证书颁发机构”的“公钥”来解密该证书,如果能解密则说明该证书是“证书颁发机构”颁发的,且没有被篡改过的。然后通过解密所得的“域名”、“证书有效期”来校验该证书是否为该网站所有,是否过期等。

本文介绍的只是“数字证书”申请和验证的基本的流程,实际流程比这个复杂很多,关于“数字证书”的信息介绍可以参考《HTTPS 权威指南》

六、HTTPS

在 HTTP 请求过程中,客户端与服务端之前没有进行身份确认,而且传输的数据都没有加密处理,所以很容易被劫持和篡改。

基于 HTTP 协议的这些弊端,后面就出现了HTTPS严格的说,HTTPS 并不是一个协议,所以前面文章都没有使用“HTTPS 协议”),HTTPS 是基于SSL/TSL协议的,说白了就是HTTP+SSL/TSL,可以把 HTTPS 大致理解为“HTTP Over SSL”或者“HTTP Over TSL”

HTTP, SSL/TSL, HTTPS 的关系如下图:

6.1 SSL/TSL 协议

6.1.1 SSL

SSL(英文:Secure Sockets Layer的缩写)中文叫“安全套接层”。最开始由 NetScape 公司研发,用以保障互联网上数据传输的安全,利用数据加密技术确保数据在网络上之传输过程中不会被截取及窃听。
SSL 协议在 TCP/IP 协议栈中位于传输层应用层之间。以HTTPS为例,SSL 协议就位于 TCP 和 HTTP 之间:

6.1.2 TLS

TLS(英文:Transport Layer Security的缩写)中文叫“传输层安全协议”,TLS 1.0是 IETF(Internet Engineering Task Force,Internet 工程任务组)制定的一种新的协议,它建立在SSL 3.0协议规范之上,是SSL 3.0的后续版本,可以理解为 SSL 3.1,它定义在RFC5246中。

因为 TLS 是基于 SSL 3.0 的,所以也可以认为 TLS 是 SSL 的加强版。

我们一般将二者并称为SSL/TSL协议,因为这二者可以视为同一个产品的不同阶段。

6.2 SSL/TSL 协议的握手过程

在了解 SSL/TSL 协议的握手过程之前,需要先阅读关于 HTTPS 的前几篇文章,对相关预备知识有所了解。

参考上面的流程图,握手过程可以分为 4 个步骤:

1). 客户端发送 Client Hello 请求到服务端,包含如下内容:

  • SSL 或 TSL 协议的版本

  • 客户端生成的随机串Client random

  • 客户端支持的加密算法列表,用于客户端和服务端加密算法的协商;

  • 客户端支持的 HASH 算法;

    2). 服务端发送 Sever Hello 响应到客户端,包含如下内容:

  • 服务端生成的随机串Server random(第 3 步会用到);

  • 由“CA 证书机构”颁发的证书的Public key部分(Public keyPrivate Key为一对,用于非对称加密和解密);

  • 会话 ID

  • 协商的加密算法(对称加密和非对称加密)和 HASH 算法。

    3). 客户端发送 Client Key 到服务端,包含如下内容或步骤:

  • 检查服务端返回的“证书”的有效性,如果无效则在浏览器上显示警告。

  • 客户端使用前 2 步生成的Client randomServer random作为随机因子,生成另外一个随机串Premaster

  • 使用Public key(第 2 步服务端返回)非对称加密的随机串Premaster

    4). 服务端通知客户端握手结束,包含如下内容:

  • 通过解密出来的Premaster生成的本次会话的Session key

  • 前面所有握手内容的 HASH 值,供客户端校验。

参考:
http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html > http://www.ruanyifeng.com/blog/2014/09/illustration-ssl.html

文章图片带有“CSDN”水印的说明:
由于该文章和图片最初发表在我的CSDN 博客中,因此图片被 CSDN 自动添加了水印。