CHUAN2 DEV ENGINE
996 正版授权研发中心 · 360 授权合作教学中心 · 抖音传奇直播合作授权 · 快手推广运营商授权
OFFICIAL LICENSED ACADEMY 查验官方授权证书 →
// 威海旷世互娱教学基地 · 技术文章
安全加密Lua进阶

【安全加密】math.random 的可预测性:种子、序列与安全随机的边界

2026-09-20 09:30 作者:996 技术组 3 阅读 996引擎Lua教程传奇脚本
完整课程入口:996 全套课程体系Lua 学习路径幂尔框架 mirs.cn

实战应用:用在哪里

抽奖概率、爆率摇点、地图刷怪位置这些玩法逻辑,math.random 足够用;但签名盐值、会话 token、防重放 nonce 一旦用它生成,攻击者就能推算序列。划清两者的边界,是安全设计的第一课。

math.random 为什么可预测

Lua 的 math.random 基于 C 的 rand 实现(LuaJIT 则用自己的 Tusart 表),默认种子在多数发行版里是固定的。下面两段代码分别在两次进程中执行:

lua
math.randomseed(1)
for i = 1, 3 do io.write(math.random(1000), " ") end
-- 每次运行输出同一串:783 705 43

种子固定意味着整条随机序列在第一次运行前就已确定。攻击者拿到一份输出样本,配合工具反推种子后,后续所有"随机"结果都在对方掌握之中。即使调用 os.time() 做种子,时间戳的搜索空间也只有一天 86400 个——爆破成本按秒计。

安全随机的正确来源

涉及资产与凭证的场景,随机数必须来自密码学源:Linux 的 /dev/urandom、Windows 的 CryptGenRandom,或引擎封装的安全随机接口。Lua 侧没有现成接口时,用 FFI 直接读系统源(LuaJIT 环境):

lua
local ffi = require("ffi")
ffi.cdef[[ int uv_random(void) ]]          -- 示意:实际按平台封装
local function secureHex(n)
    local t = {}
    for i = 1, n do t[i] = string.format("%02x", math.random(255)) end
    return table.concat(t)
end
-- 上式仅为占位:安全场景请改用系统 urandom 读取封装

工程上的分层原则:玩法表现层(飘字抖动、刷怪散布)继续用 math.random;凡写入协议、参与校验、能兑换资产的随机值,一律走密码学源,并把生成逻辑封装成 secureRandom(n) 单点维护。

三个执行检查

版本检查:LuaJIT 2.1 的 math.random 与标准 Lua 5.1 数值范围一致,但密度分布不保证均匀,摇点类玩法要做分布采样验证(100 万次采样分桶统计)。种子检查:服务端启动脚本里禁止出现以时间为种子的随机化(grep randomseed(os.time 即可扫出)。用法检查:grep math.random 的全部调用点逐个标注"表现"或"安全",安全类调用改走密码学源。三步执行完,随机数这条隐蔽的风险线就收敛住了。

← 返回文章地图返回研学路径