远程事件:连接证明发送者,载荷仍只是请求

自动关联目录:远程事件:连接证明发送者,载荷仍只是请求

核心判断:DS 可以信任“这条消息来自哪条连接”,不能信任客户端随消息传来的玩家、对象、位置、伤害或完成结果。

一、实际设计:传输层已经守住两条底线

创作者远程事件在发送前递归拒绝函数、线程和裸 userdata,避免编解码器静默把不支持的值变成 nil。服务端接收时,发送者身份由拥有该 RPC Actor 的网络连接解析,再传给脚本 handler;特殊握手还明确忽略 envelope 中自报的玩家 key。入站消息先入队,帧边界再快照并派发,重入发送延后到下一轮。

这些实践解决了类型丢失、伪造发送者和网络回调重入三个基础问题。使用稳定树路径作为 endpoint 身份,也比依赖各进程可能分叉的本地对象号更可靠。

二、边界:可序列化不等于业务合法

一个完全合法的 table 仍可以包含越界位置、无所有权对象、已经过期的交互序号或超大嵌套结构。通用传输不知道某个 endpoint 是“请求开门”还是“造成伤害”,无法替业务证明冷却、距离、状态和权限。

如果脚本直接把 OnServerEvent 参数写进权威状态,安全性就取决于每个创作者是否记得校验。全局发送队列和包长限制也不能替代按玩家、按 endpoint 的速率与计算预算。

三、目标设计:RemoteEvent 只提交 Command Envelope

CommandEnvelope
  endpointId
  schemaVersion
  requestId
  clientSequence
  payload
remote:BindServer({
    schema = MoveRequestV2,
    rate = {burst = B, sustained = R},
    authorize = function(ctx, cmd)
        return owns(ctx.player, cmd.actor)
           and withinReach(ctx.player, cmd.target)
           and currentEpoch(cmd.actor) == cmd.epoch
    end,
    execute = function(ctx, cmd)
        return movementService:TryCommit(ctx.player, cmd)
    end
})

框架先验证深度、节点数、字节、有限数值、Schema 和速率,再把“连接派生的发送者上下文”与 payload 一起交给领域授权器。结果用 Receipt 返回接收、拒绝或提交版本,不让一次事件同时冒充命令和权威状态。

四、验证

需要覆盖伪造玩家、重放 requestId、乱序 sequence、过期 epoch、超深 table、包洪泛、handler 抛错和 endpoint 销毁后迟到包。指标至少包括按拒绝原因计数、每 endpoint CPU、队列年龄和限流命中。

这里应保留连接派生身份和帧边界派发,但必须进一步明确:传输层证明来源,领域层证明请求能否改变世界。