跳到主要内容

HTTP安全问题指的是什么?

关于这个问题,我们首先要理解HTTP是什么。HTTP 是 HypeText Transfer Protocol。 是应用层协议,HT则指明内容格式为超文本(可以简单的理解加了超链接(a标签)的文本,实现文本间的交叉引用)。

HTTP消息一共有两类:

  • 从客户端发出来的是 请求消息;
  • 从服务端发出来的是 响应消息。

HTTP消息的结构是面对行数据的。文本形式,简单可读,包括:

消息组成请求消息示例响应消息示例说明
Start line(第一行)GET /test/a.html HTTP/1.0HTTP/1.0 200 OK表明请求或响应发生了什么
Header fields(头部字段)Accept:text/*
Accept-Language: en,for
Content-type: text/plain
Content-length: 19
每个头字段为 key:value,最后一定加一个空行
Body(消息体)Hi I'm a message !空行后面是可选的消息体,可以包含任何类型的数据发生给服务器或者响应给客户端,可以是非文本

如上的HTTP消息在进行完全的知识共享(早期发明的目的正是这个)时没有任何问题,但是随着应用范围的扩展,如何保证 "Alice 给 Bob 发了消息M" 确实是 "Alice 给 Bob 发了消息M" 这种问题就出现了。概括的说,就是如下四类问题:

  • 机密性:传输内容可能被窃听
  • 完整性:传输内容可能被篡改
  • 认证:伪装者伪装为发送者
  • 不可否认性:发送者事后称自己没做过

HTTP安全问题本质上是信息安全问题。

密码学应用角度的信息安全问题的概述

信息安全密码学上的技术

说 HTTP安全问题,需要打个岔一下密码学。从使用的角度而言,信息安全说面临的威胁及其密码技术主要有:

信息安全问题问题总结应对的密码技术
窃听(秘密泄露)机密性对称密码、非对称密码
篡改(信息被修改)完整性单向散列函数、消息认证码、数字签名
伪装(伪装成真正的发送者)认证消息认证码、数字签名
否认(事后称自己没有做)不可否认性数字签名

密码技术概述为:

  • 对称密码:又叫共享密钥密码。使用相同的密钥进行加密和解密
    • 解决问题:消息的机密性
    • 基本原理是:$A\ XOR\ b\ XOR\ b = A$。字节序列异或两次会得到自身
    • 常见算法有:
      • DES: Data Encryption Standard(不安全)
      • AES: Advanced Encryption Standard。用于取代DES。15个候选算法最终 Rijndael 被选中
    • 存在的问题:密钥配送(Diffie-Hellman密钥协商算法 或者 非对称密码)
  • 非对称密码:又叫公钥密码。发送者用公钥对明文加密得到密文,接收者用私钥对密文解密得到明文
    • 解决问题:消息的机密性
    • 常见算法:
      • RSA:(名字是三个作者的名字的首字母)
        • 基本原理是:Encryption 和 Number 组成公钥,Decryption 和 Number 组成私钥。 $cipertext = (plaintext ^ E)\ mod\ N, plaintext = (cipertext^D) \ mod \ N$
        • (进一步的基本原理请看数学推导,保证安全是大整数质因数分级没有快速算法)
      • ECC:椭圆曲线密码(见说明1)
    • 存在的问题:
      • 没有解决公钥配送的问题(中间人攻击):发送者拿到了中间人的公钥,中间人解密后再用接收者的公钥加密发给接收者
  • 单向散列函数:one-way hash function。输入是消息,输出是 hah value。相同的输入会得到相同的输出。
    • 解决问题:消息的完整性
    • 常见算法:
      • MD4/5: Message Digest 的缩写。(不安全)
      • SHA-1: Secure Hash Algorithm。不安全
      • SHA-256/384/512: 都是SHA-2
      • SHA-3: 一个叫 Keccak 的算法
    • 存在的问题:
      • 没有解决认证的问题。
  • 消息认证码:Message Authentication Code。
    • 解决问题:消息的发送者认证 —— 防伪装
    • 基本原理:将共享密钥和消息混合后得到散列值。发送方计算并发送,接收方接收后计算再对比(伪装者没有共享密钥)
    • 常见算法:
      • 单向散列函数。叫HMAC。 H 就是 Hash的简写。比如 HMAC-SHA-256
      • 分组密码,比如AES的CBC模式(将最后一个分组的密文当做MAC值)
    • 存在的问题:
      • 没有解决第三方认证:接收者无法向第三方证明消息来自某个发送方(数字签名)。进一步的,也办法解决否认的问题。
  • 数字签名:Digital signature
    • 解决问题:消息的发送者认证-防否认
    • 基本原理:签名密钥只有签名者持有,验证密钥所有人验证者都可以持有(非对称密码反过来用即可)
    • 常见算法:直接对消息签名(不常用),也可以对消息的散列值签名
    • 存在的问题:无法解决公钥确实是属于真正的发送者(证书)

基于上面的各种算法的组合使用,会得到 混合密码系统。TLS就是一个典型的例子。

说明1:ECC:Elliptic Curve Cryptography。 椭圆曲线密码密钥短但是强度高,其不仅仅解决加解密的问题,包括:

  • 基于椭圆曲线的公钥密码。比如 ECC
  • 基于椭圆曲线的数字签名。比如 ECDSA
  • 基于椭圆曲线的密钥交换。比如 ECDH ECDHE

密钥协商算法

还需要讲一下密钥协商算法。对称密码中遗留了一个问题:密钥如何配送。

这个问题其实是一个无解的问题:在解决数据传输安全问题上,我们要先安全的传输数据(密钥)。那换一个思路:如果密钥不需要传输呢?

没错,就有一个用作者名称命名的、叫 Diffie Hellman 的算法可以完成密钥协商,从而实现双方只需要在网络中传输各自的部分信息、但双方都能计算得到一样的结果(这个就是协商的结果,可以作为共享密钥使用)。

基本流程如下:

R1 = $G^A \ mod \ P$

R2 = $G^B \ mod \ P$

Alice                      Bob

生成质数 P、G
生成随机数 A
计算 R1
------- P、G、R1------>

生成随机数 B
计算 R2
<------- R2 ----------


使用 P、G、A、R2 得到密钥 使用 P、G、B、R1 得到密钥

数学表达式是:

AliceKey = $R2^A \ mod \ P = (G^B \ mod \ P)^A \ mod \ P = G^{B*A} \ mod \ P$

BobKey = $R1^B \ mod \ P = (G^A \ mod \ P)^B \ mod \ P = G^{A*B} \ mod \ P$

Alice 和 Bob 得到的结果是一样的,但是结果本身本没有在网络中传输。而想通过传输的数据反向破解却非常难(有限域的离散对数问题)。

还有一个ECDH的协商算法。总体流程不变,但是底层的数据问题不同(ECDH是 椭圆曲线上的离散对数问题)。在使用中了解ECDH能够用较短的密钥长度能实现较高的安全性即可。

公钥证书

在讲数字签名时遗留了一个问题:用户如何确认公钥来源于发送者,而不是攻击者?

想象中间人攻击:

Alice                中间人            Bob

请求公钥 ->
<- 返回MPK
发送 MPK加密的明文->
解密得到明文
...

这个问题也看起来是个无解的问题。这时候就需要 “第三方担保”:

  • 第三方组织认证其他的公钥的真实性(担保公钥确实来自于真实的所有者)
  • 客户端绝对相信某些可信的第三方组织(其公钥被内置在客户端)

证书是什么?

平时我们所说的证书,全称是公钥证书(Public-Key Certificate),简单的理解就是:为公钥加上数字签名得到的内容。

证书的内容

证书本身是一个文件,使用的是 ASN.1 (Abstract Syntax Notation One) 标准来结构化 描述 证书。描述如下:

Certificate  ::=  SEQUENCE  {
// 签名的内容
tbsCertificate TBSCertificate,
// 证书的签名算法
signatureAlgorithm AlgorithmIdentifier,
// 签名的值
signatureValue BIT STRING
}

TBSCertificate ::= SEQUENCE {
// 版本号,当前有INTEGER { v1(0), v2(1), v3(2) }
version [0] EXPLICIT Version DEFAULT v1,
// 证书编号,一个整数
serialNumber CertificateSerialNumber,

// 这个在Certifcate 中也出现了
signature AlgorithmIdentifier,

// 有效期
validity SEQUENCE {
notBefore Time,
notAfter Time
},

// 证书本身的公钥信息
subjectPublicKeyInfo SEQUENCE {
// 服务器公钥对应的算法(比如RSA, ECC)
algorithm AlgorithmIdentifier,
// 服务器公钥值
subjectPublicKey BIT STRING
},

// 颁发者
issuer Name,
// 颁发者(CA)编号,字符串
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version shall be v2 or v3
// 申请证书的机构
subject Name,
// 申请者(服务器实体)编号,字符串。早期是域名
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version shall be v2 or v3
// 一系列 扩展
// 一个证书可能包含多个域名,对应的就是SAN(Subject Directory Attributes)
extensions [3] EXPLICIT Extensions OPTIONAL
-- If present, version shall be v3
}

Extension ::= SEQUENCE {
extnID OBJECT IDENTIFIER,
critical BOOLEAN DEFAULT FALSE,
extnValue OCTET STRING
}

AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL
}

注意,这里面有两个 AlgorithmIdentifier(不包括冗余的那个),分别对应的是 证书本身的签名算法和证书中公钥的加密算法。

证书的分类 根据域名进行分类:

  • 单域名证书:一个证书只包含一个域名(www.a.com)
  • 泛域名证书:一个证书包含一个域名的所有的直接子域名(*.a.com)
  • SAN证书:一个证书包含多个域名(a.com 和 a.org)
  • SAN泛域名证书:一个证书包含多个普通域名或者泛域名(*.a.com 和 3.a.org)

根据审核的严格程度,也可以分为:

  • Domain Validated
  • Organization Validated
  • Extended Validated

证书如何认证公钥的真实性

虽然一直在说用的是数字签名技术,但是并没有详细说明流程。

当客户端得到了服务端发送的证书后,根据X.509标准解析证书:

  1. 域名校验:校验客户端访问的域名和证书的SAN包含的域名是否匹配
  2. 日期校验:确认证书是否在有效期内
  3. 扩展校验:如果扩展Critical为True,客户端必须正确处理该扩展
  4. 公钥校验:证书得到Key Usage 扩展需要包括 Digital Signature 和 Key Encipherment

这些校验完成之后,就要认证(服务器实体)证书本身的真实性了:

  1. 根据扩展中的 Authority Key Identifier 找到上一级证书(服务端发送完整证书链的好处在用客户端不需要再额外寻找中间证书)
  2. 确认当前证书的签发者(issuer)是上一级证书的使用者(subject)
  3. 使用上一级证书中的公钥(subjectPublicKeyInfo字段),校验当前证书的签名(signature)是否正确

至此,客户端证书校验完成了 —— 如何确认 “上一级” 证书的真实性呢?答案是:“更上一级”,直到根证书。

                                                    |-服务器实体 证书-|
| 服务器实体名称 |
|---中间 证书--| | 服务器公钥 |
| 中间CA名称 | ---签发者---| CA签发者 |
|---根 证书--| | 中间CA公钥 | --验证签名->| 签名 |
| 根CA名称 | ---签发者---| CA签发者 | |---------------|
| 根CA公钥 | --验证签名->| 签名 |
| 签名 | |-------------|
|-----------| 中间证书可以有很多
自验证签名

上面的的依赖关系叫 证书链,里面的证书分为3类:

  • 根证书:也叫自签名证书
  • 中间证书:就是在中间的证书。有上一级证书(可能是跟证书,也可能是其他中间证书)签发
  • 服务器实体证书:就是证书的使用者(比如某家公司)申请的证书。包含了域名、服务器公钥等服务器实体的信息

看百度的证书链:

GlobalSign
GlobalSign RSA OV SSL CA 2018
baidu.com

根证书是自验证的签名。那问题又来了,如何验证根证书的合法性呢?这是个社会学的问题了,好比海关为什么要相信某个国家颁发的护照? 现实生活中,操作系统会自带系统根证书,不同的软件(浏览器)也都有默认的根证书路径。

信任锚:浏览器集成了各个根证书,并充分信任这些根证书

证书如何管理

上面其实提到了几个证书有关的行为:认证、签发。就证书而言,包括的操作有:

  • 申请、签发(创建/更新)、吊销
  • 存储、获取、认证

围绕着证书有这么多的行为、流程,统称 Public Key Infrastructure 标准族(a family of standards)。而在HTTPS中使用的标准叫 X.509。PKI规定了证书的作用和结构(ASN.1描述),证书的申请、吊销、分发,证书的校验等问题。

顺便多提几个名词:

  • ASN.1 前面提过,是一种表示法,在本上下文是用来描述PKI的。目的是支持不同平台的网络通信,与机器架构和语言无关
  • BER: basic encoding rules,基本编码规则是第一个编码标准。编码的含义就是:把内存的数据编码为二进制数据(用于传输、存储等)
  • DER:distinguished encoding rules,唯一编码规则。是BER的一个子集。是X.509依赖的 编码规则。将X.509 编码为二进制数据(就是证书文件,所以有的证书有 .DER后缀的)
  • PEM:privacy-enhanced mail的简称。就是 base64.encode(DER) 的值(ASCII编码格式)。

回到 PKI,其包括的实体有:

       +---+
| C | +------------+
| e | <-------------------->| End entity |
| r | Operational +------------+
| t | transactions ^
| | and management | Management
| / | transactions | transactions
| | | PKI users
| C | v
| R | -------------------+--+-----------+----------------
| L | ^ ^
| | | | PKI management
| | v | entities
| R | +------+ |
| e | <---------------------| RA | <---+ |
| p | Publish certificate +------+ | |
| o | | |
| s | | |
| I | v v
| t | +------------+
| o | <------------------------------| CA |
| r | Publish certificate +------------+
| y | Publish CRL ^
| | |
+---+ Management |
transactions |
v
+------+
| CA |
+------+

Figure 1 - PKI Entities
  • End entity: 证书的使用者(比如浏览器)或者 证书的申请者(subject of a certificate)(比如某家公司)
  • CA: certification authority。证书签发机构。证书的申请者递交Certificate Signing Requst(证书签名请求) 的身份被审核后给其签发证书
  • RA: registration authority。主要负责证书申请者的身份审核。一般CA包括了RA
  • repository:一个存储证书和 Certificate Revocation List(证书吊销列表) 存储和获取的分布式系统

从具体流程的角度看证书的生命周期:

  |----------|             |-------------|           |--------|
| | ---1 CSR--> | |---2 CSR-->| |
| 证书订阅人 | | 登记机构 | | CA |
| | <--4 证书--- | (验证身份) |<--3 证书--| |
|----------| |-------------| |--------|
部署|证书 颁发|证书
| |
--------|-------------------------------------------------|----
| |
| ----------------------|
↓ ↓ ↓
|----------| |-------------| |------------|
| Web服务器 | | CRL服务器 | | OCSP服务器 |
|----------| |-------------| |------------|
a ↑ |b ↑ ↑
请| |验 | |
求| |证 | |
签| |签 | |
名| |名 | |
| ↓ | |
|---------| | |
| 信赖方 | | |
| (浏览器) |---->--A 吊销状态检测----|------->-----------|
|---------|

1、2、3、4 在上面大概讲过,跳过;a、b 在前面也讲过,跳过。

证书状态管理

证书可能在有效期内需要吊销,比如私钥被泄露了。这时候,浏览器就需要及时的知道。一共有两个机制完成这个工作:CRL,OCSP

CRL 是 Certificate Revocation List,证书吊销列表。是TLS/SSL协议的一部分。其是一个 全量 的被吊销的证书序列号和原因的列表。 它存在一些问题:

  • 全量意味着 越来越大,也意味着校验方需要关注不不关心的被吊销的证书,进一步的会让TLS握手时间变长(必须下载所有的CRL,不然就是分开检查(soft-fail),才能进行后面的步骤)
  • CRLs不是实时更新

OCSP 是一个 CRL 替代方案, Online Certificate Status Protocol,在线证书状态协议。最主要的差别就是其可以只查询某个证书的状态。

需要了解的是还有一个 OCSP Stapling (OCSP封套)的技术。用来解决 soft-fail校验(浏览器为了用户体验不在握手过程中校验证书的状态,而是分开、异步校验) 的问题。流程图如下:

   浏览器                     HTTPS代理               OCSP服务
| | |
| |-------OSCP请求------->|
| | |
| |<------OSCP响应--------|
| | |
| | |
|--status_request扩展 请求-->| |
| | |
|<--CertificateStatus 子消息-| |
| | |

CertificateStatus扩展tls1.1后才支持。


参考:

  • 《图解密码技术》,结城浩 著
  • 《深入浅出HTTPS》
  • 《HTTPS权威指南》
  • RFC2459: Internet X.509 Public Key Infrastructure: Certificate and CRL Profile
  • RFC6960: Internet X.509 Public Key Infrastructure: Online Certificate Status Protocol - OCSP