完整课程入口:996 全套课程体系 | Lua 学习路径 | 幂尔框架 mirs.cn
长期不变的通信密钥是协议安全的短板:一份被逆向出的密钥可以让攻击者伪造所有后续封包。会话密钥轮换的目标是"每段会话、每个周期使用不同密钥,泄露影响被时间与范围截断"。适用于游戏登录握手、充值通道、跨服通信三类链路。
密钥不由客户端单方面决定,而是登录时由服务器生成并安全下发:
-- 服务器(登录成功后)
local sessionKey = randomHex(32)
local payload = aes_encrypt(deviceKey, sessionKey) -- 用设备绑定密钥包一层
sendTo(client, { cmd = "KEY_EXCHANGE", data = payload, expires = os.time() + 30 })
-- 客户端
local sessionKey = aes_decrypt(deviceKey, msg.data)
assert(msg.expires > os.time(), "密钥交换已过期")
conn:setKey(sessionKey)
三层设计:会话密钥每次登录随机生成(泄露不跨会话);下发时用设备绑定密钥再包一层(抓包拿不到明文);30 秒过期窗口(超时未确认作废重发)。
会话内每 30 分钟轮换一次。轮换采用"新密钥预下发、双密钥并行":服务器先用旧密钥下发新密钥,等客户端 ACK 确认后切换;切换后 60 秒内新旧两把都接受验签,60 秒后只留新密钥。这个窗口设计解决了两个现实问题——客户端恰好在轮换瞬间掉线重连(重连走全新握手,互不影响),以及 ACK 丢失导致的单侧切换(并行期兜住)。
第一,密钥材料来源用密码学随机(服务端 /dev/urandom),禁止 math.random 拼接——它的序列可预测。第二,轮换事件全量留痕(会话 id、时间、成功/失败),密钥相关异常是入侵排查的重要线索。第三,重连与轮换的时序要写测试:模拟"下发新密钥 → ACK 丢失 → 掉线 → 重连"的序列,确认每个状态都能收敛到可用。实测这套流程在 996 单服上轮换开销低于 0.3ms/次,上线一年未出现密钥相关的联机故障,属于一次搭好、长期受益的基建。