fix(阶段3): 去掉判题机 token 的弱默认值

F5:token 校验实现本身是对的(用了 timingSafeEqual),问题是缺省值
"oj2-dev-token" 写死在仓库里 —— 写死在仓库里的 token 等于没有 token。

后端改为对齐旧后端 options/options.py:93 的 fail-safe:
env 缺失时生成随机值并在启动日志里告警,判题机连不上,但不会静默用弱默认值。
compose 改为 ${OJ2_JUDGE_TOKEN:?...},未设置直接报错退出。

本地开发怎么设写在 docker/compose.dev.yml 顶部与 .env.example 里:
两个变量名不同(判题机镜像认 TOKEN,后端认 JUDGE_SERVER_TOKEN)但值必须相同。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-07 01:59:27 -06:00
parent 8237909d00
commit b7adf2993d
3 changed files with 39 additions and 3 deletions

View File

@@ -1,7 +1,12 @@
DATABASE_URL=postgres://onlinejudge:onlinejudge@localhost:5433/onlinejudge DATABASE_URL=postgres://onlinejudge:onlinejudge@localhost:5433/onlinejudge
REDIS_URL=redis://localhost:6380 REDIS_URL=redis://localhost:6380
JUDGE_SERVER_URL=http://localhost:8081 JUDGE_SERVER_URL=http://localhost:8081
JUDGE_SERVER_TOKEN=oj2-dev-token # 判题机 token自己生成不要用固定值。
# TOKEN=$(openssl rand -hex 32)
# echo "JUDGE_SERVER_TOKEN=$TOKEN" >> .env # 后端读这里
# echo "OJ2_JUDGE_TOKEN=$TOKEN" >> docker/.env # 判题机容器读这里,两边必须一致
# 留空的话后端会随机生成一个并在启动日志里告警,判题机心跳会被 403 挡掉。
JUDGE_SERVER_TOKEN=
JUDGE_CONCURRENCY=2 JUDGE_CONCURRENCY=2
OJ2_DEV_USERNAME=student OJ2_DEV_USERNAME=student
OJ2_DEV_PASSWORD=student123 OJ2_DEV_PASSWORD=student123

View File

@@ -1,3 +1,22 @@
import { randomBytes } from "node:crypto"
/**
* 判题机 token。对齐旧后端 `options/options.py:93`
* token = os.environ.get("JUDGE_SERVER_TOKEN"); return token if token else rand_str()
* env 缺失时生成随机值 fail-safe —— 宁可判题机连不上(启动时有明显告警),
* 也不要在仓库里写死一个人人都知道的弱默认值。
*/
function judgeServerToken() {
const fromEnv = process.env.JUDGE_SERVER_TOKEN
if (fromEnv) return fromEnv
console.warn(
"[config] JUDGE_SERVER_TOKEN 未设置,已生成一次性随机 token。" +
"判题机将无法通过鉴权,本地开发请在 .env 里设置 JUDGE_SERVER_TOKEN" +
"并让 docker/compose.dev.yml 的 OJ2_JUDGE_TOKEN 取同一个值。",
)
return randomBytes(32).toString("hex")
}
export const config = { export const config = {
port: Number(process.env.PORT ?? 3000), port: Number(process.env.PORT ?? 3000),
redisUrl: process.env.REDIS_URL ?? "redis://localhost:6380", redisUrl: process.env.REDIS_URL ?? "redis://localhost:6380",
@@ -5,7 +24,7 @@ export const config = {
sessionTtlSeconds: Number(process.env.SESSION_TTL_SECONDS ?? 7 * 24 * 60 * 60), sessionTtlSeconds: Number(process.env.SESSION_TTL_SECONDS ?? 7 * 24 * 60 * 60),
secureCookies: process.env.COOKIE_SECURE === "true", secureCookies: process.env.COOKIE_SECURE === "true",
judgeServerUrl: process.env.JUDGE_SERVER_URL ?? "http://localhost:8081", judgeServerUrl: process.env.JUDGE_SERVER_URL ?? "http://localhost:8081",
judgeServerToken: process.env.JUDGE_SERVER_TOKEN ?? "oj2-dev-token", judgeServerToken: judgeServerToken(),
judgeConcurrency: Number(process.env.JUDGE_CONCURRENCY ?? 2), judgeConcurrency: Number(process.env.JUDGE_CONCURRENCY ?? 2),
avatarDirectory: process.env.AVATAR_DIRECTORY ?? "data/avatar", avatarDirectory: process.env.AVATAR_DIRECTORY ?? "data/avatar",
avatarUriPrefix: process.env.AVATAR_URI_PREFIX ?? "/public/avatar", avatarUriPrefix: process.env.AVATAR_URI_PREFIX ?? "/public/avatar",

View File

@@ -6,6 +6,16 @@
# #
# PostgreSQL 固定 16与生产版本16.10)一致 —— 别图新换 17/18 # PostgreSQL 固定 16与生产版本16.10)一致 —— 别图新换 17/18
# 开发环境用了生产不支持的特性,要到切换那天才炸。 # 开发环境用了生产不支持的特性,要到切换那天才炸。
#
# 判题机 token 必须自己生成,仓库里不留默认值。第一次起服务前:
#
# TOKEN=$(openssl rand -hex 32)
# echo "OJ2_JUDGE_TOKEN=$TOKEN" >> docker/.env # docker compose 读这里
# echo "JUDGE_SERVER_TOKEN=$TOKEN" >> .env # 后端读这里,两边必须一致
#
# 两个变量名不同但值必须相同TOKEN 是判题机镜像认的名字JUDGE_SERVER_TOKEN 是后端认的名字。
# 忘了设 OJ2_JUDGE_TOKEN 的话 docker compose 会直接报错退出;忘了设 JUDGE_SERVER_TOKEN
# 的话后端会随机生成一个并在启动日志里告警,判题机心跳会被 403 挡掉。
services: services:
postgres: postgres:
@@ -63,7 +73,9 @@ services:
environment: environment:
SERVICE_URL: http://oj2-judge:8080 SERVICE_URL: http://oj2-judge:8080
BACKEND_URL: http://host.docker.internal:3000/api/judge-server/heartbeat BACKEND_URL: http://host.docker.internal:3000/api/judge-server/heartbeat
TOKEN: ${OJ2_JUDGE_TOKEN:-oj2-dev-token} # 没有默认值是故意的:写死在仓库里的弱 token 等于没有 token
# 未设置时 docker compose 直接报错,不会静默起一个人人可连的判题机。
TOKEN: ${OJ2_JUDGE_TOKEN:?请先设置 OJ2_JUDGE_TOKEN见本文件顶部注释}
extra_hosts: extra_hosts:
- "host.docker.internal:host-gateway" - "host.docker.internal:host-gateway"
mem_limit: 512m mem_limit: 512m