# replay-guard Specification ## Purpose TBD - created by archiving change add-request-auth-replay-guard. Update Purpose after archive. ## Requirements ### Requirement: 时间窗校验 mjava 基座 SHALL 拒绝时间戳超出配置窗口的请求,以限制重放攻击的有效窗口。 #### Scenario: 时间戳在窗口内 - **WHEN** `X-MJ-Timestamp` 与服务端当前时间差 ≤ `mjava.auth.window`(默认 300 秒) - **THEN** 进入后续 Nonce 与签名校验 #### Scenario: 时间戳超窗 - **WHEN** 时间差 > `window`(无论提前还是滞后) - **THEN** 返回 `401 { code: "AUTH_TIMESTAMP_OUT_OF_WINDOW" }` - **AND** 审计日志记录 `clientTimestamp` 与 `serverTimestamp` 供排查 ### Requirement: Nonce 去重 mjava 基座 SHALL 通过 Nonce 缓存实现在时间窗内的一次性请求保证。同一 Nonce 在窗口期内只允许通过一次。 #### Scenario: 首次 Nonce 被接受 - **WHEN** 请求携带之前未见过的 `X-MJ-Nonce` - **THEN** `NonceCache.putIfAbsent(nonce)` 成功 - **AND** 请求进入签名校验 #### Scenario: Nonce 被重放 - **WHEN** 请求携带之前已见过的 Nonce(仍在 TTL 内) - **THEN** `NonceCache.putIfAbsent` 返回 false - **AND** 返回 `401 { code: "AUTH_NONCE_REPLAYED" }` #### Scenario: Nonce 缓存容量上限 - **WHEN** `NonceCache` 达到 `mjava.auth.nonce-cache-size` 上限 - **THEN** 按 LRU 策略淘汰最旧条目 - **AND** 淘汰不影响未淘汰 Nonce 的判定正确性 ### Requirement: Nonce 缓存 TTL 设置 `NonceCache` 的 TTL MUST 略长于 `mjava.auth.window`,以避免边界时间戳被错误接受。 #### Scenario: TTL 等于窗口 + 30s - **WHEN** NonceCache 初始化 - **THEN** TTL = `mjava.auth.window + 30` 秒 - **AND** 例:window=300 → TTL=330 ### Requirement: 单实例内存限制声明 Phase 1 的 Nonce 去重 SHALL 在单 JVM 实例内生效;多实例部署时同一 Nonce 可能被两个实例各接受一次。这是已知限制,不在本 change 范围。 #### Scenario: 多实例部署告警 - **WHEN** 生产部署判定需要多实例横向扩展 - **THEN** 运维必须评估是否升级为分布式 Nonce(Redis),独立走新 change 提案 - **AND** 本 change 的 NonceCache 配置 `nonce-cache-size` 建议单实例足够承载高峰 QPS × window 秒的组合