布隆过滤器必须在请求入口校验,不能进入业务层再查;所有user_id、sku_id等参数须在Controller或RedisTemplate.get()前经BloomFilter.contains()判定,否则无效请求将穿透至Redis和数据库。

布隆过滤器必须在请求入口就校验,不能等进业务层再查
布隆过滤器不是缓存组件,是请求安检门。所有 user_id、sku_id 类参数,在进入 Controller 或调用 RedisTemplate.opsForValue().get() 前,就必须被 BloomFilter.contains() 判定。否则攻击者发 1000 次 id=-1,全都会打到 Redis 和 DB。
常见错误写法:在 service 方法里先 redis.get("user:" + id),没命中才 new BloomFilter() 校验——这时请求早已穿透两层。
正确位置包括:
- Spring Boot 的
HandlerInterceptor.preHandle() - API 网关(如 Spring Cloud Gateway 的 GlobalFilter)
- Nginx + Lua(用
resty.bloomfilter模块)
冷启动必须预热:上线前用全量合法 ID 调用 bloomFilter.add(),否则首波请求误判率接近 100%。
空值缓存要存字符串标记,且 TTL 必须严格控制
只写 redis.setex("user:-1", 300, null) 是危险的——Jedis 可能抛异常,Lettuce 默认不存 null,业务层读出来就是 null,无法区分“真没数据”和“缓存失效”。
统一用可识别的字符串标记空值:
- 存
"NULL"(全大写)或"__EMPTY__" - TTL 设为 5–300 秒:太长(如 1 小时)会让恶意 key 占满内存;太短(如 1 秒)起不到拦截效果
- 读取时显式判断:
if ("NULL".equals(value)) { return null; },不用== null
高频异常 ID(如连续 5 次 id=select、id=1' OR '1'='1)应直接拒绝,不写缓存、不查 DB,并记录日志告警。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
拦截器里必须做轻量级 ID 合理性校验
布隆过滤器防不住语义非法但格式合法的请求,比如手机号 13800138000 符合正则,但该号码根本没注册过;分页参数 page=10000 格式没问题,但数据库只有 50 页数据。
拦截器中对 ID 参数应做三步检查:
- 数值型 ID:用
Long.parseLong()解析,捕获NumberFormatException;再判断是否 > 0 且 ≤ 2147483647 - 字符串型编号(如订单号):用正则预筛,例如
^ORD_[0-9]{8,12}$,不匹配直接 400 - 禁止原始用户输入参与 key 拼接:
"user:" + rawInput必须改成"user:" + validatedUserId
注意:@Min(1) 这类注解默认不生效,必须配合 @Valid + 全局 @RestControllerAdvice 才真正起作用。
Redis 配置本身必须加固,否则布隆和空值都白搭
如果 Redis 开放在公网、无密码、以 root 运行,黑客连上后直接 FLUSHALL 或写入 SSH 公钥,整个防护体系瞬间崩塌。
生产环境最低配置要求:
-
bind 127.0.0.1:禁用公网监听,只允许本机访问 -
requirepass YourStrongPassword123!:设置强密码,重启生效 - 用普通用户(非 root)运行 Redis 进程
- 禁用高危命令:
rename-command CONFIG ""、rename-command FLUSHALL "" - 防火墙限制:仅允许应用服务器 IP 访问 6379 端口
真正拦住穿透的,从来不是某个 Redis 命令,而是你在 redis.get() 前那几行校验逻辑、布隆过滤器的部署位置、以及 Redis 服务本身的最小权限运行——这三者缺一不可,任何一个环节松动,攻击者就能绕过去。

















