Skip to content

Security: guscherer/ibrpubg

Security

docs/SECURITY.md

Security Guide

This guide documents all security features implemented in the IBR Tournament System and how to use them effectively.

Table of Contents


Overview

The IBR Tournament System implements defense-in-depth security with multiple layers of protection:

  • Authentication: Password hashing, MFA, OAuth integration
  • Session Security: Encrypted sessions, secure token storage
  • Rate Limiting: Sliding window algorithm with IP and user tracking
  • Input Validation: Zod schemas with sanitization
  • Encryption: AES-256-GCM for sensitive data at rest
  • Audit Logging: Comprehensive security event tracking
  • Infrastructure: CI/CD security scanning, environment validation

All security features are designed to be:

  • Transparent: Don't impact legitimate user experience
  • Monitored: Generate audit trails for compliance
  • Tested: Full test coverage for all security components

Authentication Security

Password Requirements

Passwords must meet the following criteria:

  • Minimum 8 characters
  • At least one uppercase letter (A-Z)
  • At least one lowercase letter (a-z)
  • At least one number (0-9)
  • At least one special character (!@#$%^&*)

Implementation: See apps/api/src/middleware/validation.ts - commonSchemas.password

Password Storage

  • Passwords are hashed using bcrypt with 10 salt rounds
  • Plain-text passwords are never stored or logged
  • Password change events are logged to password_change_events table

Code Reference: apps/api/src/handlers/auth.ts - handleRegister()

Login Flow

  1. User submits username/password
  2. System validates input format
  3. Rate limiting is checked (3 attempts per 5 minutes)
  4. Credentials are verified against bcrypt hash
  5. Successful login is logged to login_attempts table
  6. Failed login is logged with failure reason
  7. Session is created if MFA is not enabled
  8. MFA verification is required if enabled

Security Checks:

  • Rate limiting prevents brute force attacks
  • Account lockout after multiple failed attempts (feature can be enabled)
  • Audit trail of all login attempts

Multi-Factor Authentication (MFA)

Overview

MFA adds an additional layer of security using TOTP (Time-based One-Time Password) compatible with:

  • Google Authenticator
  • Authy
  • Microsoft Authenticator
  • Any TOTP-compatible app

Enabling MFA

Users can enable MFA via:

  • API Endpoint: POST /api/auth/mfa/setup
  • Frontend Settings page (when implemented)

Flow:

  1. User requests MFA setup
  2. System generates TOTP secret
  3. System returns QR code for scanning
  4. User scans QR code with authenticator app
  5. User submits 6-digit code to verify
  6. MFA is enabled for the account

MFA Endpoints

// Setup MFA - returns QR code
POST /api/auth/mfa/setup
Authorization: Bearer <session_token>

// Verify and enable MFA
POST /api/auth/mfa/enable
Body: { code: "123456" }
Authorization: Bearer <session_token>

// Disable MFA (requires password confirmation)
POST /api/auth/mfa/disable
Body: { password: "current_password" }
Authorization: Bearer <session_token>

// Verify MFA during login
POST /api/auth/mfa/verify
Body: { code: "123456" }
Authorization: Bearer <session_token>

MFA Storage

  • TOTP secrets are encrypted using AES-256-GCM before storage
  • Encryption key: SESSION_ENCRYPTION_KEY environment variable
  • Encrypted secrets stored in users.mfa_secret column

MFA Events

All MFA events are logged to mfa_events table:

  • Setup initiated
  • Setup completed
  • Verification attempts (success/failure)
  • MFA disabled

Session Management

Session Storage

Sessions are stored in Cloudflare KV with the following structure:

Key: session:<token>
Value: {
  userId: string,
  username: string,
  role: string,
  mfaEnabled: boolean,
  mfaVerified: boolean,
  createdAt: string,
  expiresAt: string
}
TTL: 7 days (configurable)

Session Security Features

  1. Encryption: Session data is encrypted before storage
  2. Token Generation: Cryptographically secure random tokens
  3. Expiration: Automatic expiration after 7 days
  4. MFA Tracking: Separate MFA verification flag
  5. Audit Trail: All session events logged

Session Lifecycle

Create → Verify (with MFA if enabled) → Refresh → Destroy/Expire

Events Logged:

  • session.create: New session created
  • session.destroy: User logged out
  • session.refresh: Session extended
  • session.expire: Session timed out

Session Endpoints

// Create session (after successful login)
POST /api/auth/login
Body: { username, password }

// Refresh session
POST /api/auth/refresh
Authorization: Bearer <session_token>

// Destroy session (logout)
POST /api/auth/logout
Authorization: Bearer <session_token>

Rate Limiting

Overview

Rate limiting prevents abuse and brute force attacks using a sliding window algorithm.

Rate Limits by Endpoint

Endpoint Type Limit Window Description
Authentication 5 requests 60 seconds Login, register, password reset
Login 3 requests 300 seconds Strict limit on login attempts
MFA Setup 3 requests 3600 seconds MFA configuration
MFA Verify 10 requests 300 seconds MFA code verification
Password Reset 3 requests 3600 seconds Password reset requests
API Read 100 requests 60 seconds GET requests
API Write 30 requests 60 seconds POST/PUT/PATCH requests
API Delete 10 requests 60 seconds DELETE requests
Admin Read 200 requests 60 seconds Admin GET requests
Admin Write 50 requests 60 seconds Admin POST/PUT/PATCH

Rate Limit Response Headers

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1708800000
Retry-After: 30

Rate Limit Algorithm

Sliding Window:

  • Tracks timestamps of all requests
  • Counts requests within the time window
  • More accurate than fixed window algorithms
  • Prevents burst attacks at window boundaries

Admin Bypass

Admin users can bypass rate limits:

  • Automatic bypass for users with role: 'admin'
  • Useful for bulk operations
  • Logged for audit purposes

Configuration

Rate limits are configured in apps/api/src/middleware/enhanced-rate-limit.ts:

export const RATE_LIMIT_CONFIGS = {
  login: { limit: 3, window: 300, keyPrefix: 'rl:login' },
  apiRead: { limit: 100, window: 60, keyPrefix: 'rl:api:read' },
  // ... more configs
};

Input Validation

Validation Strategy

All user input is validated using Zod schemas with the following layers:

  1. Schema Validation: Type checking, format validation
  2. Sanitization: HTML tag stripping, SQL injection detection
  3. Length Limits: Prevent DoS via large inputs
  4. Pattern Matching: Email, UUID, username formats

Common Validation Schemas

// Email validation
email: z.string().email('Invalid email format')

// Username validation (3-20 chars, alphanumeric + underscore + hyphen)
username: z.string()
  .min(3, 'Username must be at least 3 characters')
  .max(20, 'Username must not exceed 20 characters')
  .regex(/^[a-zA-Z0-9_-]+$/, 'Username can only contain letters, numbers, underscores, and hyphens')

// Password validation (8+ chars, uppercase, lowercase, number, special)
password: z.string()
  .min(8, 'Password must be at least 8 characters')
  .regex(/[A-Z]/, 'Password must contain at least one uppercase letter')
  .regex(/[a-z]/, 'Password must contain at least one lowercase letter')
  .regex(/[0-9]/, 'Password must contain at least one number')
  .regex(/[^a-zA-Z0-9]/, 'Password must contain at least one special character')

// UUID validation
uuid: z.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)

Sanitization

SQL Injection Detection:

const sqlPatterns = [
  /(\b(SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|TRUNCATE)\b)/i,
  /(--|;|\/\*|\*\/)/,
  /\b(OR|AND)\s+\w+\s*(=|<|>|\!=)/i,
  /(\bUNION\s+SELECT\b)/i,
];

sanitizers.hasSqlInjection(input); // Returns true if detected

XSS Detection:

const xssPatterns = [
  /<script[^>]*>.*?<\/script>/gi,
  /<iframe[^>]*>.*?<\/iframe>/gi,
  /javascript:/i,
  /on\w+\s*=/i, // onclick=, onload=, etc.
];

sanitizers.hasXss(input); // Returns true if detected

Usage in Handlers

import { withValidation, requestSchemas } from '../middleware/validation';

// Automatic validation
export const handleLogin = withValidation(
  requestSchemas.login,
  async (request) => {
    const { username, password } = request.validatedData;
    // Process login...
  }
);

Encryption

Encryption Service

All encryption uses AES-256-GCM (Galois/Counter Mode) which provides:

  • Confidentiality: Data cannot be read without the key
  • Integrity: Tampering is detected
  • Authenticated Encryption: Combines encryption and authentication

Encryption Keys

Primary Key: SESSION_ENCRYPTION_KEY environment variable

  • Must be 32+ characters
  • Used for all encryption operations
  • Never expose in logs or error messages

Key Rotation (future enhancement):

  • Implement key versioning
  • Re-encrypt data with new keys
  • Support multiple key versions

Encrypted Data

The following data is encrypted at rest:

  • MFA secrets (users.mfa_secret)
  • OAuth refresh tokens (oauth_accounts.refresh_token)
  • Session data (in KV storage)
  • Any future sensitive user data

Encryption Functions

// Encrypt string data
const encrypted = await encryptData("sensitive data", env);

// Decrypt string data
const decrypted = await decryptData(encrypted, env);

// Encrypt objects
const encryptedObj = await encryptObject({ key: "value" }, env);
const decryptedObj = await decryptObject<MyType>(encryptedObj, env);

// Hash for integrity verification
const hash = await hashData("data");
const isValid = await verifyHash("data", hash);

Audit Logging

Audit Tables

The following tables track security-relevant events:

Table Purpose
login_attempts All login attempts (success/failure)
admin_actions Admin operations for accountability
password_change_events Password changes and resets
oauth_events OAuth linking/unlinking/login
session_events Session lifecycle
mfa_events MFA setup and verification
rate_limit_events Rate limit violations
data_export_events GDPR data export requests

Audit Event Structure

All audit events include:

  • id: Unique event identifier
  • created_at: Event timestamp
  • ip_address: Client IP address
  • user_id: Affected user (if applicable)
  • Additional fields specific to event type

Querying Audit Logs

import { createAuditService } from '../services/audit-service';

const auditService = createAuditService(env);

// Get failed login attempts for a user
const failedLogins = await auditService.getFailedLoginAttempts('username', 60);

// Get recent admin actions
const adminActions = await auditService.getRecentAdminActions(100);

// Get user activity history
const activity = await auditService.getUserActivity('user-id');

// Get security metrics for dashboard
const metrics = await auditService.getSecurityMetrics(24);

Compliance

The audit log system supports:

  • GDPR: Complete user activity tracking
  • SOC2: Comprehensive security monitoring
  • Forensic Analysis: Incident response data
  • Accountability: Admin action tracking

OAuth Security

Supported Providers

  • Google OAuth 2.0
  • GitHub OAuth 2.0

OAuth Flow

  1. User clicks "Sign in with [Provider]"
  2. Redirect to provider's authorization page
  3. User grants permissions
  4. Provider redirects back with authorization code
  5. Server exchanges code for access token
  6. Server fetches user profile
  7. Account is linked or created
  8. Session is created
  9. OAuth event is logged

Token Storage

  • Access tokens are stored in oauth_accounts table
  • Refresh tokens are encrypted before storage
  • Tokens are never logged or exposed in errors
  • Tokens can be revoked via OAuth provider

OAuth Security Features

  • State Parameter: CSRF protection during OAuth flow
  • PKCE (future): Proof Key for Code Exchange
  • Token Encryption: Refresh tokens encrypted at rest
  • Audit Logging: All OAuth events logged
  • Revocation: Users can unlink OAuth accounts

Security Headers

Implemented Headers

The following security headers are automatically added to all API responses:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Content-Security-Policy: default-src 'self'
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), microphone=(), camera=()

Configuration

Headers are defined in apps/api/src/middleware/security-headers.ts:

export const SECURITY_HEADERS = {
  'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload',
  'X-Content-Type-Options': 'nosniff',
  'X-Frame-Options': 'DENY',
  // ... more headers
};

Environment Configuration

Required Environment Variables

Variable Purpose Requirements
SESSION_ENCRYPTION_KEY Session encryption 32+ characters
JWT_SECRET JWT signing 32+ characters
PUBG_API_KEY PUBG API access Valid API key
ENVIRONMENT Environment name development/staging/production
CORS_ORIGIN Frontend origin Valid URL

Validation at Startup

The application validates all environment variables at startup:

import { validateOnStartup } from './services/environment-validation';

// In src/index.ts
validateOnStartup(env);

Development: Warns about issues but continues Production: Fails startup if validation fails

Feature Flags

Control features via environment variables:

# Enable/disable MFA
ENABLE_MFA=true

# Enable/disable OAuth
ENABLE_OAUTH=true

# Enable/disable new user registration
ENABLE_REGISTRATION=false

CI/CD Security

Automated Scans

Security scans run automatically on:

  • Every push to main/master/develop branches
  • Every pull request
  • Daily schedule (2 AM UTC)

Scan Types

  1. Dependency Vulnerability Scan: npm audit, pnpm audit
  2. Secret Detection: TruffleHog scans full git history
  3. Code Security: ESLint with security rules, TypeScript type checking
  4. SAST: Semgrep, CodeQL for vulnerability patterns
  5. License Compliance: Checks for GPL/AGPL/SSPL licenses

Local Security Checks

Run security checks locally before committing:

# Full security scan
npm run security:check

# Install pre-commit hooks
npm run security:install-hooks

Pre-Commit Hook

Automatically runs before every commit:

  • Secret detection
  • Large file warnings
  • Dangerous pattern detection
  • Linting staged files

Monitoring and Alerting

Security Metrics

Track these metrics for security monitoring:

const metrics = await auditService.getSecurityMetrics(24);

console.log({
  failedLogins: metrics.failedLogins,
  successfulLogins: metrics.successfulLogins,
  adminActions: metrics.adminActions,
  passwordChanges: metrics.passwordChanges,
  mfaEvents: metrics.mfaEvents,
  rateLimitExceeded: metrics.rateLimitExceeded,
});

Alerts to Configure

Recommended alerts for monitoring systems:

  1. High Failed Login Rate: >10 failed logins per minute
  2. Rate Limit Violations: >100 per hour
  3. Admin Actions: All admin actions (for review)
  4. MFA Disable Events: When users disable MFA
  5. Password Reset: Multiple resets for same user

Dashboards

Create dashboards showing:

  • Failed vs successful login attempts
  • Rate limit violations over time
  • MFA adoption rate
  • Active sessions
  • Recent admin actions

Best Practices

For Developers

  1. Never commit secrets

    • Use environment variables
    • Add sensitive files to .gitignore
    • Use pre-commit hooks
  2. Validate all input

    • Use Zod schemas
    • Sanitize user input
    • Check for SQL injection/XSS
  3. Log security events

    • Use audit service
    • Include context (IP, user, timestamp)
    • Never log sensitive data
  4. Encrypt sensitive data

    • Use encryption service
    • Never store plain-text secrets
    • Use strong encryption keys
  5. Follow principle of least privilege

    • Minimize permissions
    • Use read-only when possible
    • Validate admin actions

For Operations

  1. Rotate encryption keys quarterly
  2. Review audit logs weekly
  3. Update dependencies regularly
  4. Monitor security metrics daily
  5. Test security features monthly

Security Checklist

Before Deployment

  • All required environment variables set
  • Encryption keys are strong (32+ chars)
  • CORS origin configured correctly
  • Rate limiting enabled
  • MFA enabled for production
  • Audit logging configured
  • Security headers in place
  • Dependency scan passing
  • No secrets in code
  • Database migrations applied
  • SSL/TLS configured
  • Monitoring/alerting configured

After Deployment

  • Monitor failed login rate
  • Review audit logs for issues
  • Test rate limiting
  • Verify MFA flow
  • Check OAuth integration
  • Validate session management
  • Review security metrics

Troubleshooting

Common Issues

Problem: Users seeing rate limit errors Solution:

  • Check rate limit configuration
  • Verify admin bypass working
  • Review rate limit metrics

Problem: MFA verification failing Solution:

  • Check system time synchronization
  • Verify TOTP secret encryption
  • Test with manual TOTP code

Problem: Login failures increasing Solution:

  • Review failed login logs
  • Check for brute force attacks
  • Consider lowering rate limits

Problem: Session expiration issues Solution:

  • Verify KV storage working
  • Check session TTL configuration
  • Review session event logs

Additional Resources


For questions or security concerns, contact the security team or open a security issue in the repository.

There aren’t any published security advisories