会话存在 Redis 里(session:<token> → 用户 id),能连上它就能伪造任意用户包括超管的 登录态。旧栈起的 oj-redis 发布在 0.0.0.0:5446、不带口令,2026-09-27 从公网实测 PING 得通。 - compose.debian.yml:REDIS_URL 用 ${REDIS_PASSWORD:?} 带上口令,缺了直接报错; 自带数据形态的 oj-redis 加 --requirepass,端口只发布在 127.0.0.1 - deploy.sh:外接形态下实测「不带口令连不上、带 docker/.env 的口令连得上」, 任一条不满足就中止部署 - clear-sessions.sh:从 docker/.env 读口令走 REDISCLI_AUTH;口令为空时不带 -e (空的 REDISCLI_AUTH 会发一条 AUTH "",实测会报一行 AUTH failed) - compose.dev.yml:三个端口只绑 127.0.0.1 - docs/deploy.md 加「Redis 口令」一节:给旧栈 redis 加口令的一次性步骤 旧栈那份 compose 不在本仓库,线上 redis 的口令要照手册在服务器上手工加; 加之前 deploy.sh 会一直拦着。机房的 redis 不发布端口,不需要口令。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`sh docker/clear-sessions.sh` 在 Debian 上会用 dash 跑(/bin/sh 就是它), 第 34 行的 `set -euo pipefail` 里 pipefail 是 bash 专有的,脚本一上来就死在 `Illegal option -o pipefail`,正事一件没干。deploy.sh 里早就有同一道垫片, 写这个脚本时漏抄了。 实跑验证(dev 栈,`sh docker/clear-sessions.sh`):垫片生效后跑到容器探活 那步正常报错;`CONTAINER=oj2-redis YES=1 sh docker/clear-sessions.sh` 全程 走通 —— session:* 删 101 个、user-sessions:* 删 4 个、bull:* 前后都是 57 个 (dbsize 162 → 57,判题队列一个键没动)。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XvmqDsZNyUo9P3sFQtoWVB
反向索引 user-sessions:<uid> 是 498fc1c 才加的,在那之前签发的会话不在索引里, revokeUserSessions 靠 SMEMBERS 找不到它们 —— 改密码、重置密码、禁用账号对这批会话 统统无效,只能等最长一个 SESSION_TTL_SECONDS(默认 7 天)自然过期。学生密码是明文 存着给老师查的,改密码正是密码泄露后唯一的补救手段,这个空窗不留。代价是所有人重新 登录一次。跑过一次就不用再跑,此后签发的会话都带索引。 **两个站点都要跑。** 机房和服务器共用一个数据库,但各有各的 Redis,会话存在各自的 Redis 里,只清一边等于只解决一半。脚本结尾会提醒这件事。 只删 session:* 和 user-sessions:*,不用 FLUSHALL:同一个 Redis 里还装着 BullMQ 的 判题队列,清掉等于把还在队列里的提交全丢了,那些 submission 会永远停在 PENDING。 删完会核对 bull:* 的键数没变,变了就报错让人工检查。 扫描用 SCAN 不用 KEYS(KEYS 会阻塞住整个 Redis,而这上面还挂着所有人的会话读写), xargs 分批 DEL 避免顶到命令行长度上限。 拿一次性容器验过:1200 条 session + 50 条索引全删(跨过分批边界),30 个 bull 键和 throttling 桶原样不动;空库上重跑是幂等的;容器名写错时报错退出不做任何事。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XvmqDsZNyUo9P3sFQtoWVB
498fc1c