Skip to content

fix(deploy): 修复 Redis command YAML 折叠陷阱导致 --requirepass 静默失效#4028

Open
Chena2003 wants to merge 1 commit into
Wei-Shaw:mainfrom
Chena2003:fix/redis-command-yaml-fold
Open

fix(deploy): 修复 Redis command YAML 折叠陷阱导致 --requirepass 静默失效#4028
Chena2003 wants to merge 1 commit into
Wei-Shaw:mainfrom
Chena2003:fix/redis-command-yaml-fold

Conversation

@Chena2003

@Chena2003 Chena2003 commented Jul 11, 2026

Copy link
Copy Markdown

问题

三个 Docker Compose 文件中 Redis 服务的 command 使用 YAML folded scalar (>):

command: >
  sh -c '
    redis-server
    --save 60 1
    --appendonly yes
    --appendfsync everysec
    ${REDIS_PASSWORD:+--requirepass "$REDIS_PASSWORD"}'

sh -c ' 行的缩进(4 空格)比后续参数行(8 空格)浅,按 YAML > 折叠规则,更深缩进的行之间保留换行符而非折叠成空格。解析结果:

["sh", "-c", "\n  redis-server\n  --save 60 1\n  ..."]

shell 把换行当作命令分隔符,redis-server无参数默认配置启动,--save--appendonly--requirepass 全部静默失效。因为 redis-server 是前台阻塞进程,后续行永远不会执行。

后果:即使 .env 中设置了 REDIS_PASSWORD,Redis 仍以无密码运行。端口映射虽然已在 #18790386 移除,但若攻击者通过其他途径进入 Docker 内网,Redis 仍处于无认证状态。

修复

改为数组形式 command + >- 折叠标量:

command:
  - sh
  - -c
  - >-
    exec redis-server --save 60 1 --appendonly yes --appendfsync everysec
    ${REDIS_PASSWORD:+--requirepass "$REDIS_PASSWORD"}
  • 数组形式确保 sh 精确收到三个参数,无歧义
  • >- 将同缩进行的换行折叠为空格,sh -c 收到完整的单行命令
  • execredis-server 替换 sh 进程成为 PID 1,正确接收 Docker SIGTERM

验证

# 有密码
$ POSTGRES_PASSWORD=dummy REDIS_PASSWORD=testpass123 docker compose -f deploy/docker-compose.yml config
# redis.command 解析为:
# exec redis-server --save 60 1 --appendonly yes --appendfsync everysec --requirepass "testpass123" ✓

# 无密码
$ POSTGRES_PASSWORD=dummy docker compose -f deploy/docker-compose.yml config
# redis.command 解析为:
# exec redis-server --save 60 1 --appendonly yes --appendfsync everysec ✓

三个文件均已验证:

  • deploy/docker-compose.yml
  • deploy/docker-compose.dev.yml
  • deploy/docker-compose.local.yml

Fixes #2511
Fixes #291

Redis 服务的 command 使用 YAML folded scalar (>), 但 sh -c 后的参数行
缩进更深,YAML 保留换行而非折叠成空格。shell 把换行当作命令分隔符,
导致 redis-server 以无参数默认配置启动,--save / --appendonly /
--requirepass 全部静默失效。

改为数组形式 command + >- 折叠标量,确保所有参数在同一行传给 sh -c,
并加 exec 让 redis-server 成为 PID 1 正确接收 SIGTERM。

验证: docker compose config 确认解析后的 command 为单行完整命令,
REDIS_PASSWORD 设置时 --requirepass 正确生效,未设置时正确省略。

涉及文件:
- deploy/docker-compose.yml
- deploy/docker-compose.dev.yml
- deploy/docker-compose.local.yml
@github-actions

github-actions Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA. ✅
Posted by the CLA Assistant Lite bot.

@Chena2003

Copy link
Copy Markdown
Author

补充:实际安全事件背景

这个 YAML 陷阱不是理论上的问题,我在生产环境中已经因为它遭遇了一次 Redis 未授权访问安全事件。以下是经过简化的复盘,供维护者参考这个 bug 的实际危害。

事件经过

  1. 部署使用了本仓库的 docker-compose.yml.env 中设置了 REDIS_PASSWORD
  2. 由于 YAML 折叠陷阱,--requirepass 从未生效,Redis 一直以无密码默认配置运行
  3. 早期版本 ports: 6379:6379 将 Redis 暴露到公网(已在 18790386 移除)
  4. 攻击者扫描到公网 6379 端口,无需认证直接连入
  5. 攻击者执行 REPLICAOF <攻击者IP> <端口>,将 Redis 变为只读从节点
  6. 攻击者同时尝试通过 CONFIG SET dir /etc/cron.d + SET backup1-4 + SAVE 植入挖矿木马 cron 任务

用户感知

Redis 变成只读从节点后,所有写操作被拒绝。登录接口的限流中间件(fail-close 策略)对 Redis 执行 INCR 失败,直接返回 HTTP 429。用户看到的是:

Too many requests, please try again later

无论换 IP、等多久都无法登录。排查后发现 redis-cli INFO replication 显示:

role:slave
master_host:109.244.159.27
master_port:24848
master_link_status:down
master_current_sync_attempts:41870

41870 次同步重试意味着 Redis 已被入侵约 5 天。

为什么没造成严重后果

  • 主从复制 RCE 未成功:攻击者的恶意主节点连接失败(master_link_status: down
  • cron 注入未落地:Redis 在 Docker 容器内,/etc/cron.d 是容器内的路径,容器内没有运行 cron 进程
  • 攻击者扫描是无差别蠕虫式攻击,非针对性

实际损失

  • Redis 缓存数据丢失(可重建的调度状态、临时 token)
  • 已登录用户会话失效,需重新登录
  • 无核心数据泄露(PostgreSQL 完好,.env 未被读取)
  • 短暂服务中断

教训

这个 bug 的危险之处在于静默失败:配置看起来正确,容器启动正常,业务能跑,没有任何报错。只有被攻击时才暴露。如果端口暴露的问题没有在 18790386 修复,配合这个 YAML 陷阱,任何使用本仓库 compose 部署且设置了 REDIS_PASSWORD 的用户都会误以为自己有密码保护,实际上 Redis 完全裸奔。

希望这个 PR 能防止其他用户踩到同样的坑。

@Chena2003

Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA

github-actions Bot added a commit that referenced this pull request Jul 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Redis Password Configuration Failure via .env Update [bug]: docker-compose.yml语法错误

1 participant