EVALSHA 因 Redis 仅校验 SHA1 缓存而无脚本内容校验,伪造哈希会返回 NOSCRIPT 错误;应兜底 fallback 到 EVAL、启动时预加载脚本、启用 ACL 限制权限,并遵守集群键槽一致性规则。

为什么 EVALSHA 会因伪造哈希报错?
因为 EVALSHA 不校验脚本内容,只查 Redis 内部缓存里有没有对应 SHA1 值。如果客户端传了个随机或错误的哈希(比如 "deadbeef..."),Redis 找不到匹配脚本,直接返回 NOSCRIPT No matching script. Please use EVAL. —— 这不是安全拦截,而是单纯“没加载过”,和恶意无关,但可能被滥用试探或触发异常路径。
如何避免伪造哈希导致流程中断?
核心是别让 EVALSHA 成为唯一入口,加一层兜底逻辑:
- 执行
EVALSHA后捕获异常,检查错误信息是否含"NOSCRIPT"关键字 - 命中则自动 fallback 到
EVAL,传入完整脚本字符串重试(首次执行时顺便完成预加载) - 生产环境建议在应用启动时预加载关键脚本:调用
SCRIPT LOAD并缓存其返回的 SHA1,后续全走EVALSHA - Spring Data Redis 的
RedisTemplate.execute()默认已内置该 fallback 逻辑;若用原生 Jedis/Redisson,请自行封装
真正防“恶意”得靠权限控制,不是哈希校验
EVALSHA 本身不防攻击,它只是执行机制。防止未授权 Lua 执行,必须靠 ACL:
- Redis 6.0+ 必须启用 ACL,禁用非可信用户的
EVAL和EVALSHA权限:ACL SETUSER myapp -EVAL -EVALSHA +@read +@write - 不要依赖
lua-time-limit 0禁用脚本——它只是把超时设为 0 毫秒,实际会导致所有 Lua 立即失败,且不是设计用途 - 禁止暴露 Redis 给公网;如需远程调用,走带鉴权的中间服务,而非直连 Redis
容易被忽略的集群陷阱:哈希一致 ≠ 脚本安全
即使你用了正确 SHA、也配了 ACL,在 Redis 集群中仍可能因键分布出错而失败,这不是伪造哈希的问题,但常被混淆:
- 脚本里所有
KEYS[1]、KEYS[2]必须落在同一哈希槽,否则报ERR bad lua script:... keys in same slot - 不能在脚本里拼接 key 名(如
"user:"..ARGV[1]),必须由客户端通过KEYS数组显式传入 - 集群模式下,
SCRIPT LOAD和EVALSHA必须路由到包含目标 key 的节点,Jedis/Redisson 一般自动处理,但自研客户端要手动确保

















