跳到主要内容

附录 C. 认证问题

本附录描述一种可选认证机制, 可用于验证 NTP 消息完整性, 并防止消息修改和重放攻击. 该机制基于 MD5 加密哈希函数, 并在 peer 之间使用共享密钥. 启用认证时, 包含 key identifier 和 message digest 的 authenticator 字段会追加到 NTP 消息后.

认证机制提供以下安全服务:

  1. 消息完整性: 确保消息在传输过程中未被修改.
  2. 源认证: 验证消息来自持有共享密钥的合法 peer.
  3. 重放保护: 与 NTP 时间戳机制结合时, 提供对重放攻击的防护.

认证机制是可选的, 不必在所有情况下实现. 但是, 当安全性很重要时, 尤其是在未授权时间服务器可能注入虚假时间信息的环境中, 认证机制提供了一种有效保护手段.

C.1. NTP 认证机制

NTP 认证机制使用 MD5 加密哈希函数, 对 NTP 消息和共享密钥计算 message digest. 该 message digest 连同标识所用密钥的 key identifier 一起追加到 NTP 消息的 authenticator 字段中.

Authenticator 字段格式如下:

 0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Key Identifier |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| Message Digest |
| |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Key Identifier: 这是一个 32 位无符号整数, 标识用于生成 message digest 的加密密钥.

Message Digest: 这是一个 128 位 MD5 哈希, 对 NTP 消息 (直到但不包括 authenticator 字段) 和共享密钥计算得到.

共享密钥手动配置, 存储在 NTP daemon 可访问的密钥文件中. 每个密钥都有唯一标识符, 并表示为 64 位 (8 八位组) 值. 密钥格式与 DES 加密算法兼容, 但 DES 不直接用于认证机制.

C.2. NTP 认证过程

认证过程在发送和接收操作期间调用. 启用认证时, transmit 过程计算 message digest 并将 authenticator 追加到出站消息. receive 过程验证入站消息上的 authenticator, 并相应设置 authenticated bit.

C.2.1. 加密过程

启用认证时, transmit 过程会调用 encrypt 过程. 它计算 MD5 message digest, 并将 authenticator 追加到 NTP 消息.

begin encrypt procedure
if (peer.authenable = 0) exit; /* authentication disabled */

/* Append key identifier */
pkt.keyid <- peer.hostkeyid;

/* Compute MD5 digest over message and key */
digest <- MD5(message || key[peer.hostkeyid]);

/* Append digest to message */
pkt.check <- digest;

end encrypt procedure

MD5 计算覆盖整个 NTP 消息 (包括 NTP 头部和时间戳字段), 随后是共享密钥. 得到的 128 位 digest 会追加到消息的 authenticator 字段中.

C.2.2. 解密过程

decrypt 过程由 receive 过程调用, 用于验证入站消息上的 authenticator. 它使用所指示的密钥重新计算 message digest, 并与收到消息中的 digest 进行比较.

begin decrypt procedure
if (peer.authenable = 0) begin /* authentication disabled */
peer.authentic <- 1;
exit;
endif

/* Check if key identifier is valid */
if (pkt.keyid not in sys.keys) begin
peer.authentic <- 0;
exit;
endif

/* Extract received digest */
received_digest <- pkt.check;

/* Compute expected digest */
expected_digest <- MD5(message || key[pkt.keyid]);

/* Compare digests */
if (received_digest = expected_digest)
peer.authentic <- 1;
else
peer.authentic <- 0;

end decrypt procedure

如果认证成功 (digest 匹配), authenticated bit (peer.authentic) 设置为 1, 表示消息来自合法 peer. 如果认证失败, 该 bit 设置为 0, 并且根据配置, 消息可能被拒绝.

C.2.3. 控制消息过程

当附录 B 描述的 NTP 控制消息实现了认证时, 使用相同认证机制. encrypt 和 decrypt 过程以与常规 NTP 消息相同的方式应用.

对控制消息而言, 认证尤其重要, 因为这些消息可用于读取和修改 NTP 实现的内部变量. 如果没有认证, 攻击者可能扰乱时间同步或提取敏感信息.

实现考虑

实现认证机制时应考虑以下事项:

  1. 密钥管理: 必须在所有将使用认证的 peer 上手动配置共享密钥. 应定期更换密钥以维持安全性.

  2. 性能影响: 计算 MD5 digest 会给每条消息增加处理开销. 在 CPU 资源有限的系统上, 这可能影响计时精度. 实现应在可用时考虑缓存 digest 计算或使用硬件加速.

  3. 时间戳精度: 加密操作应尽可能接近实际消息发送时刻执行, 以最小化对时间戳精度的影响. 某些实现会预先计算 digest 偏移, 以补偿加密延迟.

  4. Key Identifier 空间: 32 位 key identifier 空间允许大量密钥, 便于密钥轮换并支持多个认证域.

  5. 向后兼容性: 带认证和不带认证的消息可以共存. 不支持认证的 peer 会直接忽略 authenticator 字段.

  6. 安全限制: 认证机制可防止消息修改和重放攻击, 但不加密消息内容. 时间信息本身以明文传输.

这里描述的认证机制在大多数 NTP 部署中提供了安全性和性能之间的实用平衡. 对需要更强安全保证的环境, IPsec 或其他传输层安全机制等额外措施可能更合适.