14-认证机制
14-认证机制

14-认证机制

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

安全最佳实践

  1. 始终使用 HTTPS – 生产环境必须使用 TLS 加密传输令牌
  2. 通过 Header 传递令牌 – 虽然支持 Query 参数,但 Header 更安全
  3. 定期轮换令牌 – 建议定期更换 AUTHN_TOKEN 和 AUTHZ_TOKEN
  4. 最小化授权范围 – 仅对必要操作启用授权
  5. 结合 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

下一步

相关条目

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注