计算机网络安全:报文与实体鉴别
报文鉴别
鉴别是网络安全的核心问题之一,用于验证通信对方的真实身份和报文的完整性。和加密不同在于,加密主要用于保护信息内容不被窃取,它和鉴别可以独立和结合使用。而授权是在身份被鉴别之后,决定其访问权限,鉴别是授权的前提。鉴别主要分为报文鉴别和实体鉴别。
散列函数
直接对长报文进行数字签名(如 RSA)计算开销巨大,因此在实践中采用密码散列函数 + 数字签名的组合来实现报文鉴别。密码散列函数是一种将任意长度输入映射为固定长度输出(散列值,如 128/256 位)的单向函数,是报文鉴别的技术核心。它的核心特性如下:
| 密码散列函数特性 | 说明 |
|---|---|
| 固定输出 | 无论输入多长,输出长度固定。 |
| 抗碰撞性 | 找到两个不同的输入,使得它们的散列值相同是计算上不可行的。即给定散列值 \(H(X)\),无法伪造出另一个明文 \(Y\) 使得 \(H(Y) = H(X)\)。 |
| 单向性 | 从散列值无法反推出原始输入 |

散列值 \(H(X)\) 如同报文的数字指纹,发送方对报文 \(X\) 计算散列值并用私钥签名;接收方重新计算散列值并用公钥验证签名。若匹配,则同时证明了报文来源的真实性和内容的完整性。最典型的散列算法是 MD5 算法,其基本思想是用足够复杂的方法,使报文摘要代码中的每一位都与原来报文中的每一位有关,流程如下:
- 附加长度:在报文末尾附加原始报文的长度信息(64 位)。
- 填充:填充 1~512 位,使总长度成为 512 位的整数倍。
- 分块迭代处理:将报文分割为 512 位的数据块,每个块再与当前散列值进行多轮(4 轮)复杂的压缩函数运算,更新散列值。
- 输出:最终输出一个 128 位的散列值。

王小云教授团队在 2004 年发表系统性碰撞攻击方法,动摇了 MD5 的安全性根基。实用的密码散列函数包括 MD5 与 SHA 系列,其发展如下表总结:
| 算法 | 输出长度 | 状态 |
|---|---|---|
| MD5 | 128 位 | 已被攻破,不再安全。设计精巧,是理解散列函数的经典案例。 |
| SHA-1 | 160 位 | 已被证明不安全,正被淘汰。安全性曾优于 MD5,但同样被王小云教授团队等攻破。 |
| SHA-2 (SHA-256/384/512) | 256/384/512 位 | 当前广泛使用的安全标准,是 SHA-1 的增强版本,目前未发现有效攻击。 |
| SHA-3 | 可定制 | 采用与 MD5/SHA-2 完全不同的设计(海绵结构),作为备份和未来选项。 |
报文鉴别码
简单的明文+散列方案存在安全性问题。考虑这样一个过程:发送方 A 计算明文 \(X\) 的散列 \(H(X)\),发送 \((X, H(X))\) 给 B。B 收到后重新计算 \(H‘(X)\),与收到的 \(H(X)\) 比较。任何入侵者都可以伪造一个报文 \(M\),计算其散列 \(H(M)\),然后冒充 A 发送 \((M, H(M))\)。B 无法区分这是 A 发来的还是入侵者伪造的,因为散列函数本身是公开的,且不提供身份认证。

解决方案是使用报文鉴别码 MAC,它的核心思想对散列值进行加密,将其与一个共享的秘密密钥绑定,可以被视作带密钥的散列或密码校验和。基于对称密钥的 MAC 工作流程如下:
- 发送方 A 计算明文 \(X\) 的散列值 \(H\),用与 B 共享的秘密密钥 \(K\) 对 \(H\) 进行加密,生成 \(MAC = E_K(H)\),发送扩展报文 \((X, MAC)\) 给B。
- 接收方 B:收到 \((X, MAC)\) 后,用相同的密钥 \(K\) 对 \(MAC\) 进行解密得到 \(H\)。对收到的明文 \(X\) 重新计算散列值 \(H‘(X)\)。

通过比较 \(H\) 与 \(H’(X)\),若一致,则同时验证了报文完整性(\(X\) 未被篡改)和来源认证(MAC 是由拥有密钥 \(K\) 的一方生成的)。MAC 方案的运行效率高,它仅对短小的散列值进行加密,计算开销远小于加密整个报文。由于密钥 \(K\) 是通信双方共享的秘密,入侵者无法在不知道 \(K\) 的情况下伪造有效的 MAC,实现了鉴别功能。
最广泛使用的 MAC 构造方法是 HMAC (Hashed MAC),它可以与 MD5、SHA-1 等散列函数结合使用。HMAC 把密钥 K 拼接在明文后面,使用密码散列算法对其进行运算得出的散列值就是 HMAC。

不过,对称的 MAC 方案仍存在密钥分发问题,一个更优的方案是将 MAC 与数字签名结合。利用公钥密码体制,优化后的流程如下:
- 发送方 A 计算明文 \(X\) 的散列值 \(H\),用 A 自己的私钥 \(SK_A\) 对 \(H\) 进行数字签名,生成 \(MAC = D_{SK_A}(H)\)。MAC 实质上是对散列值的数字签名,接着 A 发送 \((X, MAC)\) 给B。
- 接收方 B 用 A 的公钥 \(PK_A\) 对 \(MAC\) 进行验证运算,还原出 \(H\),重新计算 \(H‘(X)\) 并比较。
此方案利用公钥体系解决了密钥分发难题,同时提供了报文鉴别、报文完整性、不可否认性。

实体鉴别
与报文鉴别不同,实体鉴别是在一次会话开始时对通信对方身份进行一次性验证,而非对每个报文都验证。简单的实体鉴别方法是:A 向 B 发送加密报文,内容为“身份 A + 口令”,使用双方共享的对称密钥 \(K_{AB}\) 加密,B 通过解密后验证。该策略无法应对重放攻击,攻击者 C 无需解密,只需在网络中截获并重放 A 发送给 B 的整个加密报文。B 收到后解密,会误以为 C 就是 A,接下来 C 可以冒充 A 与 B 通信,接收本应发给 A 的数据。

为应对重放攻击,可以使用不重数:一个仅使用一次的大随机数,用于区分不同的会话请求。由于每个会话使用唯一的不重数,C 截获的过往加密响应 \(\{R\}_{K_{AB}}\) 无法在新会话中重用,重放攻击失效。基于对称密钥的工作流程如下所示:
- A 发送自己的身份 \(A\) 和一个随机不重数 \(R_A\) 给B(明文)。
- B 生成自己的不重数 \(R_B\),并用共享密钥 \(K_{AB}\) 加密 A 发来的 \(R_A\),将 \(\{R_A\}_{K_{AB}}\) 和 \(R_B\) 一起发送给 A。
- A 用 \(K_{AB}\) 解密得到 \(R_A\),验证与自己发出的一致,从而确认对方是 B。然后,A用 \(K_{AB}\) 加密 B 发来的 \(R_B\),将 \(\{R_B\}_{K_{AB}}\) 发回给B。
- B 解密验证 \(R_B\),确认对方是 A。

除了不重数,也可以使用基于公钥密码的实体鉴别策略,其优点在于无需预先共享对称密钥。该策略利用数字签名替代对称加密,但使用私钥签名、公钥验证:
- A 发送 \(A\) 和 \(R_A\) 给B。
- B 用 自己的私钥 \(SK_B\) 对 \(R_A\) 签名后发回,同时发送 \(R_B\)。
- A 用 B的公钥 \(PK_B\) 验证签名,确认对方是B。然后用自己的私钥 \(SK_A\) 对 \(R_B\) 签名后发回。
- B 用 A的公钥 \(PK_A\) 验证签名,确认对方是A。

尽管公钥密码避免了密钥共享,但若公钥本身的真实性无法保证,则会面临严重攻击。例如 C 冒充 A 与 B 通信,当 B 发送 \(R_B\) 时,C 截获并用自己的私钥 \(SK_C\) 签名后发回 B,同时将自己的公钥 \(PK_C\) 冒充为 A 的公钥发送给 B。此时 B 用 \(PK_C\)(以为是 A 的)验证签名成功,误认 C 为 A。不过因为真正的 A 并无通信记录,此种攻击较易被察觉。
中间人攻击是更具欺骗性的攻击,C 将完全介入 A 与 B 的通信链路,能双向拦截、篡改和转发所有报文。攻击时 C 分别与 A 和 B 建立独立的、看似正常的连接,对 A,C 冒充 B;对 B,C 冒充 A。C 将 B 的公钥请求转发给 A,但将 A 回复的真公钥 \(PK_A\) 截留,然后将自己公钥 \(PK_C\) 冒充为 A 的公钥发给 B。反之亦然。

此时 A 和 B 都以为自己正与对方安全通信,但实际上所有通信都经过 C。C 可以解密、阅读、甚至修改 A 与 B 之间本应保密的数据,而双方浑然不觉。中间人攻击的根本原因在于:公钥在传输过程中缺乏可信的认证机制,A 和 B 都错误地相信了由中间人 C 提供的对方公钥。因此,如何安全地分配和认证公钥,成为了一个至关重要的问题。
密钥分配
由于密码算法是公开的,网络安全就依赖于保证密钥的安全,其最大难题就是密钥分配,即如何让通信双方安全地获得共享的秘密密钥。分配方式主要包括两种:
| 秘钥分配方式 | 简介 |
|---|---|
| 网外分配 | 早期通过可靠信使传递,不适用于大型、动态网络 |
| 网内分配 | 通过网络自动分配,是现代网络采用的方式 |
对称密钥的分配
对称密钥分配面临两大难题:
- n²问题:n 个用户两两通信需要 \(n(n-1)/2\) 个密钥,密钥数量随用户数平方增长,管理开销巨大。
- 传送难题:网络不安全所以需要加密,因此加密的密钥本身无法安全地传送。
解决方案是引入可信第三方密钥分配中心 KDC(Key Distribution Center),它是通信双方都信任的机构,每个用户与 KDC 之间预先共享一个长期密钥(称为主密钥)。当两个用户需要通信时,由 KDC 为他们临时生成一个会话密钥,工作流程为:
- 用户 A 向 KDC 发送明文请求,表明想与 B 通信。
- KDC 随机生成一个一次性的会话密钥 \(K_{AB}\),然后向 A 回复一个加密报文。报文包含用 A 与 KDC 的共享主密钥 \(K_A\) 加密的 \(K_{AB}\),以及用 B 与 KDC 的共享主密钥 \(K_B\) 加密的一个票据。票据内含 \(K_{AB}\) 和双方身份。A无法读取票据内容,只负责转发。
- 用户 B 用自己的主密钥 \(K_B\) 解密从 A 得到的票据获得 \(K_{AB}\),此后 A 和 B 使用 \(K_{AB}\) 进行安全会话。

密钥在网络上传输时总是加密的,KDC 可加入时间戳防止重放攻击。
Kerberos 协议
一个著名的 KDC 实现是 Kerberos 协议,它既是鉴别协议也是一个 KDC 系统,使用 AES 加密。Kerberos 引入了两个服务器来细化职责,它的工作流程如下:
- 客户 A 向鉴别服务器 AS表明身份,进行认证服务。
- AS 验证 A 的身份(如通过口令派生密钥),验证通过后 AS 向 A 发送 A 与 TGS 的会话密钥 \(K_S\)(用 A 的密钥加密),以及访问 TGS 的票据(用 TGS 的密钥 \(K_{TG}\) 加密)。A 可解密得到 \(K_S\),但无法读取票据内容。
- A 向票据授予服务器 TGS发送从 AS 获得的票据以请求的服务 B 的名称,并用 \(K_S\) 加密的时间戳防重放。
- TGS 验证票据和时间戳后,向 A 发送两个票据:给 A 的票据(用 \(K_S\) 加密)、给服务器 B 的票据(用 B 的密钥 \(K_B\) 加密),两个票据均包含
A 与 B 的会话密钥 \(K_{AB}\))。 - A 向服务器 B 转发从 TGS 获得的票据,并发送用 \(K_{AB}\) 加密的时间戳。
- B 验证票据和时间戳,将时间戳加 1 并用 \(K_{AB}\) 加密后回复 A,确认身份并完成双向认证。

Kerberos 要求所有主机时钟松散同步,所有主机的时钟误差不能太大,用于防范重放攻击,
公钥的分配
在公钥密码体制中,虽然公钥可以公开,但需要考虑如何确保一个公钥确实属于它所声称的实体(人或机器)。简单地通过网络直接交换公钥,容易遭受中间人攻击或欺骗。假设用户 A 想欺骗 B:
- A 可以伪造一份声称来自 C 的报文,用 A 自己的私钥签名。
- A 将该签名连同 A 自己的公钥一并发送给 B,却谎称这个公钥是 C 的。
- 由于 B 无法验证该公钥的真实归属,可能会相信这份伪造的报文确实来自 C。

因此需要一个可信的第三方机构来建立公钥与实体身份之间的绑定关系,解决方案是使用认证中心与数字证书。认证中心是一个值得公众信赖的权威机构,负责核实实体的身份,并为其签发数字证书。认证中心通常由政府或大型信誉良好的组织建立和维护。数字证书包含证书持有者的标识信息(如姓名、组织、域名/IP 地址)和其公钥,整个证书内容由 CA 用自己的私钥进行数字签名。任何用户都可以用 CA 的公钥来验证证书上签名的有效性。如果签名验证通过,就证明该证书的内容是真实的、未经篡改的,且得到了 CA 的背书。

数字证书的格式必须标准化,ITU-T 制定了 X.509 协议标准用于描述证书的结构,由 IETF 采用 X.509 V3 作为互联网的建议标准。证书内容如下表所示
| 数字证书内容 | 说明 |
|---|---|
| 版本号 | 区分 X.509 不同版本 |
| 序列号 | CA 发放,唯一 |
| 签名算法 | 签署证书所使用的算法和参数 |
| 发行者 | 签发者的唯一标识符 |
| 有效期 | 包括起始时间和终止时间 |
| 主体名 | 公钥和数字证书拥有者的唯一标识符 |
| 公钥 | 数字证书拥有者的公钥和使用算法的标识符 |
| 发行者 ID | 任选,唯一,标识发行者 |
| 主体 ID | 任选,唯一,标识证书持有者 |
| 扩展域 | 扩充信息 |
| 认证机构签名 | 用 CA 私钥对证书签名 |
X.509 提出把多级认证中心链接起来的,构成一个树状的认证系统,末端是用户。最高一级的认证中心都称为根认证中心 (Root CA),是公认可信的认证中心(或无条件信任的),且其公钥是公开的。

与信任链对应的是证书链,最顶层的根证书的数字签名是自签名的,即自己的私钥给自己签名。

参考资料
《计算机网络(第七版)》 谢希仁 著,电子工业出版社
《计算机网络 自顶向下方法》 [美] James F.Kurose,Keith W.Ross 著,陈鸣 译,机械工业出版社

浙公网安备 33010602011771号