bigywater.tech
Redis · 133

Redis 备份文件泄露

备份文件丢了、复制账号被盗了,会泄露什么?这篇把 RDB 和 AOF 当作攻击者手里的文件直接查找内容,再验证两件防御:限制拉全量数据的权限,以及备份加密和篡改检测。

明文
RDB 和 AOF 里 key 名与 value 都是明文;压缩只让文件变小,不是保护
~app:* 不管用
有 +psync +sync +replconf 的账号,即使 key 模式只有 app:*,也能用 redis-cli --rdb 拉走整份数据
CBC 不认证
密文翻转 1 个比特,openssl 解密仍成功(returncode 0),要靠 redis-check-rdb 或额外 MAC 发现

文件里有什么

实测 · 本机执行输出
  在文件里找                                             dump.rdb    AOF 全部
  短字符串 value  "token=abc123-SECRET"                       找到        找到
  key 名 "session:1001"                                    找到        找到
  长且重复的 value 里的标记 "CARDNUM-MARKER"                       找到        找到
  ACL 用户密码明文 "hunter2-pass"                               没有        没有
  该密码的 sha256 哈希                                          没有        没有
  Lua 脚本正文里的注释 "SCRIPT_BODY_MARKER_XYZ"                   没有        没有
  脚本产生的 value "from-script"                               找到        找到
  user:1 的 value 是 "CARDNUM-MARKER;" 重复 400 次(共 6000 字节)。dump.rdb 大小:rdbcompression yes 73058 字节,no 171958 字节;关掉压缩后标记 找到
  也就是说:压缩让文件变小,但压缩流里第一份原文仍是明文,压缩不是保护。
  redis-check-rdb 校验原文件:returncode 0 | ['[offset 73058] Checksum OK', '[offset 73058] \\o/ RDB looks OK! \\o/']

用 Python 直接在文件字节里查找,等价于 strings | grep。key 名和 value 都是明文。不在里面的:ACL 用户的密码与哈希(在 users.acl 里,第 132 篇)、Lua 脚本正文(复制的是脚本产生的写命令)。压缩:见表格最后几行,文件小了很多,但一份原文仍在。

通过复制协议拉走全量

实测 · 本机执行输出
  用户 app(ACL: ~app:* +get +set)→ 输出:sending REPLCONF capa eof / REPLCONF capa error: NOPERM User app has no permissions to run the 'replconf' command / sending REPLCONF rdb-only 1 / REPLCONF rdb-only error:
    拿到 RDB 文件:False;文件里含 app:* 以外的 key/value(session:1001 的 token):False
  用户 repl(ACL: ~app:* -@all +psync +sync +replconf +ping)→ 输出:sending REPLCONF capa eof / sending REPLCONF rdb-only 1 / SYNC sent to master, writing bytes of bulk transfer until EOF marker to '<实验目录>
    拿到 RDB 文件:True;文件里含 app:* 以外的 key/value(session:1001 的 token):True

普通应用账号(+get +set)因为没有 +replconf,redis-cli --rdb 一开始就被拒。但只要账号被授予了复制相关的命令,key 模式(~app:*)就管不住它:它拿到的是完整的 RDB。所以复制账号要单独建、单独保管,并且不要把 +psync / +sync 给应用账号。

备份加密

实测 · 本机执行输出
  加密 dump.rdb(73058 字节)→ 73088 字节,用时 22 ms;returncode=0
  加密文件里能找到 key 名 / value / 标记吗: {'session:1001': False, 'abc123-SECRET': False}
  用对的密码解密,与原文件逐字节相同: True
  用错的密码解密:returncode 1 bad decrypt
80FFA1F401000000:error:1C800064:Provider routines:ossl_cipher_unpadb
  密文中间翻转 1 个比特后解密:returncode 0 (解密本身有没有报错)
  对被篡改后解出的文件运行 redis-check-rdb:returncode 1 | ['--- RDB ERROR DETECTED ---', '[offset 36531] Invalid object type: 179']
  被篡改解出的文件与原文件相同:False;不同的字节数 17(共 73058 字节)

这里用 openssl enc 只是最小演示:AES-256-CBC + PBKDF2 + 盐,加密后找不到明文,正确密码能还原,错误密码得到 bad decrypt。CBC 模式本身不带认证,密文被改一个比特,解密照样成功、只是明文里对应位置变了——RDB 自带的校验(redis-check-rdb)这次抓到了篡改,但这是这次翻转的位置恰好落在有效数据里的结果,不能当作对所有篡改都有效。生产上应该用带认证的方案(比如带 MAC 的加密工具),本文没有测。

要做的事

分步演示:备份里有什么、怎么保护

备份文件泄露
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / Redis 8.10.2 独立实例(本机回环端口,save 关闭),redis-cli 风格输出由自写的 RESP 客户端打印;计时用 time.perf_counter,数字每次运行会有小幅抖动。所有数据都是我构造的假数据(token、卡号标记都是测试字符串)
    • 没有验证:带认证的加密(AES-GCM / age / gpg)、AOF 文件的加密与校验(redis-check-aof)、Redis 8 之外版本的 --rdb 行为、rdb-key-save-delay 之外的备份路径(如 BGSAVE 到云存储)、复制账号只给 +psync 而不给 +sync 时 redis-cli --rdb 能否成功、磁盘加密(LUKS / FileVault)
    京ICP备2026067502号-1京公网安备11010502063487号