loadstring和load不是调用外部函数,而是动态执行任意代码;它们绕过Redis沙箱,允许拼接用户输入生成并运行恶意逻辑,导致命令注入、信息泄露或DoS攻击。

loadstring 和 load 是唯一能“调用外部函数”的入口,但它们本身就是高危操作——只要出现,就等于主动绕过 Redis 的沙箱限制。
为什么 loadstring 不是“调用外部函数”,而是执行任意代码
Redis 的 Lua 环境禁用了所有系统级 API(如 os、io、package),但没禁掉 loadstring。攻击者传入 "return "..ARGV[1],再让 ARGV[1] 是 "1+1; redis.call('DEL', 'admin:token')",loadstring 会把它编译成函数并执行——虽然 redis.call 调用本身受权限控制,但逻辑已被篡改,且错误响应可能泄露 key 存在性等信息。
-
loadstring生成的函数运行在同一个 Lua state 中,能访问脚本内所有局部变量和已加载的 key/argv - 即使没直接调用危险命令,也能通过
pcall+ 类型探测、响应时间差等方式做布尔盲注 - Redis 7.2+ 已默认禁用
loadstring,但旧版本或自定义编译的 Redis 可能仍开启
redis.call() 参数被污染等于间接执行恶意逻辑
很多人误以为“没用 loadstring 就安全”,其实不然。redis.call("GET", ARGV[1]) 看似无害,但如果 ARGV[1] 是 "user:123<p>很多人误以为“没用 <code>loadstring 就安全”,其实不然。redis.call("GET", ARGV[1]) 看似无害,但如果 ARGV[1] 是 "user:123\0admin:token"(含空字符),某些 Redis 版本解析 key 时截断异常;更常见的是:ARGV[1] 是 "123 OR 1=1",虽不会 SQL 注入,但在脚本里用于 string.match(key, ARGV[1]) 就可能触发正则回溯,造成 DoS。
ARGV[1] 是 "123 OR 1=1",虽不会 SQL 注入,但在脚本里用于 string.match(key, ARGV[1]) 就可能触发正则回溯,造成 DoS。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 所有传给
redis.call()的参数必须先校验类型:用tonumber()转数字、用string.match(v, "^%w+$")限定 key 名格式 - 避免在脚本里做模式匹配,SCAN 的
MATCH比 Lua 的string.find更安全、更高效 - 数值类参数(如 INCR 步长)必须设上下界,
if not (n >= 1 and n
全局变量和未清理的 table 引发状态泄漏
Lua 脚本执行完后,全局变量(_G)会被清空,但局部变量和闭包中捕获的引用不会自动释放。如果脚本里写了 local cache = {} 并反复复用(比如缓存某个用户权限结果),而没重置或限制大小,可能撑爆内存;更危险的是把敏感数据(如 token 解密结果)存进 table 后没清空,后续脚本若因 bug 访问到残留数据,就会泄露。
- 禁止使用
global或_G写入任何值 - 所有中间 table 都应显式声明为
local,用完即弃,不复用 - 绝不把用户输入、解密结果、临时凭证存入 table 后留到下一次调用
ARGV、每个 redis.call()、每次 string.match() 都要带上下文校验——漏掉一处,就可能被当成跳板。

















