跳到主要内容

附录 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 或其他传输层安全机制等额外措施可能更合适.