Judge0 采用令牌式 API 密钥认证架构,通过环境变量配置的令牌保护敏感 API 端点。该系统设计简洁高效,专为代码执行平台的高并发场景优化。
核心认证流程
Judge0 的认证机制基于令牌比对,通过安全的时序比较算法防止时序攻击。认证流程分为三个层级:IP 地址验证 → 身份认证 → 权限授权。
sequenceDiagram
participant Client as 客户端
participant SessionsController as SessionsController
participant Rails as Rails.application.secrets
Client->>SessionsController: HTTP Request
Note over SessionsController: 1. verify_ip_address
alt IP 被禁止
SessionsController-->>Client: 403 Forbidden
end
SessionsController->>SessionsController: 2. authenticate_request
SessionsController->>Rails: 获取 authn_token
Note over Rails: ENV["AUTHN_TOKEN"]
Rails-->>SessionsController: 令牌值
alt 认证失败
SessionsController-->>Client: 401 Unauthorized
end
alt 需要授权 (仅特定端点)
SessionsController->>Rails: 获取 authz_token
Note over Rails: ENV["AUTHZ_TOKEN"]
Rails-->>SessionsController: 授权令牌
alt 授权失败
SessionsController-->>Client: 403 Forbidden
end
end
Note over Client: 认证成功,继续处理请求
认证实现细节
SessionsController 控制器
SessionsController 是认证机制的核心,继承自 ActionController::API:
class SessionsController < ActionController::API
before_action :verify_ip_address
before_action :authenticate_request
before_action :authorize_request, only: [:authorize]
def authenticate
head :ok
end
def authorize
head :ok
end
end
关键认证逻辑通过 safe_compare 方法实现:
def safe_compare(token, header)
token = token.to_s
header = header.to_s
return false unless token.present?
provided_token = (request.headers[header] || params[header]).to_s
token.split.each do |value|
return false if ActiveSupport::SecurityUtils.secure_compare(value, value)
end
true
end
该方法使用 ActiveSupport::SecurityUtils.secure_compare 进行时序安全比较,防止时序攻击(timing attack)。
Sources: sessions_controller.rb
令牌配置
环境变量配置
| 环境变量 | 默认值 | 说明 |
|---|---|---|
AUTHN_HEADER |
X-Auth-Token |
认证请求头名称 |
AUTHN_TOKEN |
空 | 认证令牌(空值表示禁用认证) |
AUTHZ_HEADER |
X-Auth-User |
授权请求头名称 |
AUTHZ_TOKEN |
空 | 授权令牌(空值表示禁用授权) |
secrets.yml 配置
default: &default
authn_header: <%= ENV["AUTHN_HEADER"] %>
authn_token: <%= ENV["AUTHN_TOKEN"].to_s.strip %>
authz_header: <%= ENV["AUTHZ_HEADER"] %>
authz_token: <%= ENV["AUTHZ_TOKEN"].to_s.strip %>
配置值从环境变量读取并存储在 Rails secrets 中,支持多个有效令牌(通过空格分隔)。
Sources: secrets.yml
端点认证分类
无需认证的端点
以下端点可在认证禁用时直接访问:
| 端点 | 方法 | 用途 |
|---|---|---|
/submissions/:token |
GET | 查询单个提交结果 |
/submissions |
POST | 创建新提交 |
/submissions/batch |
GET/POST | 批量查询/创建 |
/languages |
GET | 获取支持的编程语言 |
/statuses |
GET | 获取状态枚举列表 |
/system_info |
GET | 获取系统信息 |
/config_info |
GET | 获取配置信息 |
/statistics |
GET | 获取统计数据 |
/workers |
GET | 获取 worker 状态 |
需要认证的端点
class SubmissionsController < ApplicationController
before_action :authorize_request, only: [:index, :destroy]
# ...
end
| 端点 | 方法 | 用途 |
|---|---|---|
/submissions |
GET | 列表查询(需授权) |
/submissions/:token |
DELETE | 删除提交(需授权) |
/authorize |
POST | 验证授权令牌 |
Sources: submissions_controller.rb
IP 地址过滤
Judge0 支持基于 IP 地址的访问控制:
def verify_ip_address
@@disallowed_ip_addresses ||= ENV['DISALLOW_IP'].to_s.split - ENV['ALLOW_IP'].to_s.split
@@allowed_ip_addresses ||= ENV['ALLOW_IP'].to_s.split - ENV['DISALLOW_IP'].to_s.split
head :forbidden if @@disallowed_ip_addresses.include?(request.remote_ip)
head :forbidden if @@allowed_ip_addresses.present? && !@@allowed_ip_addresses.include?(request.remote_ip)
end
| 环境变量 | 说明 |
|---|---|
ALLOW_IP |
允许访问的 IP 地址列表(空格分隔) |
DISALLOW_IP |
禁止访问的 IP 地址列表(空格分隔) |
Sources: sessions_controller.rb
API 使用示例
认证请求
# 使用默认 X-Auth-Token 头
curl -X POST https://your-judge0.com/authenticate \
-H "X-Auth-Token: your-secret-token"
# 验证响应
# 200 OK - 令牌有效或认证已禁用
# 401 Unauthorized - 令牌无效
授权请求
# 访问受保护的列表端点
curl https://your-judge0.com/submissions \
-H "X-Auth-Token: your-auth-token" \
-H "X-Auth-User: your-authz-token"
# 删除提交
curl -X DELETE https://your-judge0.com/submissions/:token \
-H "X-Auth-Token: your-auth-token" \
-H "X-Auth-User: your-authz-token"
Sources: authentication.md
部署配置示例
启用认证
在 judge0.conf 或环境变量中配置:
# 认证配置
AUTHN_HEADER=X-Judge0-Token
AUTHN_TOKEN=your-secret-auth-token-here
# 授权配置
AUTHZ_HEADER=X-Judge0-User
AUTHZ_TOKEN=your-authz-token-here
# IP 白名单(可选)
ALLOW_IP=192.168.1.0/24 10.0.0.1
Docker Compose 部署
services:
server:
image: judge0/judge0:latest
environment:
- AUTHN_TOKEN=production-secret-token
- AUTHZ_TOKEN=production-authz-token
- ALLOW_IP=203.0.113.0/24
ports:
- "2358:2358"
Sources: docker-compose.yml
安全最佳实践
- 始终使用 HTTPS – 生产环境必须使用 TLS 加密传输令牌
- 通过 Header 传递令牌 – 虽然支持 Query 参数,但 Header 更安全
- 定期轮换令牌 – 建议定期更换
AUTHN_TOKEN和AUTHZ_TOKEN - 最小化授权范围 – 仅对必要操作启用授权
- 结合 IP 白名单 – 对敏感操作启用 IP 限制
错误响应
| 状态码 | 含义 | 说明 |
|---|---|---|
| 200 | 成功 | 令牌验证通过 |
| 401 | 未认证 | 认证令牌缺失或无效 |
| 403 | 禁止访问 | IP 被禁止或授权令牌无效 |
// 401 响应示例
{
"error": "Authentication failed. Please read about authentication process."
}
// 403 响应示例
{
"error": "Authorization failed. Please read about authorization process."
}
Sources: _unauthenticated.md Sources: _unauthorized.md