Files
mockupAWS/docs/SECURITY-CHECKLIST.md
Luca Sacchi Ricciardi cc60ba17ea
Some checks failed
E2E Tests / Run E2E Tests (push) Has been cancelled
E2E Tests / Visual Regression Tests (push) Has been cancelled
E2E Tests / Smoke Tests (push) Has been cancelled
release: v0.5.0 - Authentication, API Keys & Advanced Features
Complete v0.5.0 implementation:

Database (@db-engineer):
- 3 migrations: users, api_keys, report_schedules tables
- Foreign keys, indexes, constraints, enums

Backend (@backend-dev):
- JWT authentication service with bcrypt (cost=12)
- Auth endpoints: /register, /login, /refresh, /me
- API Keys service with hash storage and prefix validation
- API Keys endpoints: CRUD + rotate
- Security module with JWT HS256

Frontend (@frontend-dev):
- Login/Register pages with validation
- AuthContext with localStorage persistence
- Protected routes implementation
- API Keys management UI (create, revoke, rotate)
- Header with user dropdown

DevOps (@devops-engineer):
- .env.example and .env.production.example
- docker-compose.scheduler.yml
- scripts/setup-secrets.sh
- INFRASTRUCTURE_SETUP.md

QA (@qa-engineer):
- 85 E2E tests: auth.spec.ts, apikeys.spec.ts, scenarios.spec.ts, regression-v050.spec.ts
- auth-helpers.ts with 20+ utility functions
- Test plans and documentation

Architecture (@spec-architect):
- SECURITY.md with best practices
- SECURITY-CHECKLIST.md pre-deployment
- Updated architecture.md with auth flows
- Updated README.md with v0.5.0 features

Documentation:
- Updated todo.md with v0.5.0 status
- Added docs/README.md index
- Complete setup instructions

Dependencies added:
- bcrypt, python-jose, passlib, email-validator

Tested: JWT auth flow, API keys CRUD, protected routes, 85 E2E tests ready

Closes: v0.5.0 milestone
2026-04-07 19:22:47 +02:00

11 KiB

Security Checklist - mockupAWS v0.5.0

Version: 0.5.0
Purpose: Pre-deployment security verification
Last Updated: 2026-04-07


Pre-Deployment Security Checklist

Use this checklist before deploying mockupAWS to any environment.

🔐 Environment Variables

Required Security Variables

# JWT Configuration
JWT_SECRET_KEY=                          # [REQUIRED] Min 32 chars, use: openssl rand -hex 32
JWT_ALGORITHM=HS256                      # [REQUIRED] Must be HS256
ACCESS_TOKEN_EXPIRE_MINUTES=30           # [REQUIRED] Max 60 recommended
REFRESH_TOKEN_EXPIRE_DAYS=7              # [REQUIRED] Max 30 recommended

# Password Security
BCRYPT_ROUNDS=12                         # [REQUIRED] Min 12, higher = slower

# Database
DATABASE_URL=                            # [REQUIRED] Use strong password
POSTGRES_PASSWORD=                       # [REQUIRED] Use: openssl rand -base64 32

# API Keys
API_KEY_PREFIX=mk_                       # [REQUIRED] Do not change

Checklist

  • JWT_SECRET_KEY is at least 32 characters
  • JWT_SECRET_KEY is unique per environment
  • JWT_SECRET_KEY is not the default/placeholder value
  • BCRYPT_ROUNDS is set to 12 or higher
  • Database password is strong (≥20 characters, mixed case, symbols)
  • No secrets are hardcoded in source code
  • .env file is in .gitignore
  • .env file has restrictive permissions (chmod 600)

🌐 HTTPS Configuration

Production Requirements

  • TLS 1.3 is enabled
  • TLS 1.0 and 1.1 are disabled
  • Valid SSL certificate (not self-signed)
  • HTTP redirects to HTTPS
  • HSTS header is configured
  • Certificate is not expired

Nginx Configuration Example

server {
    listen 443 ssl http2;
    server_name api.mockupaws.com;
    
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
    ssl_protocols TLSv1.3;
    ssl_ciphers 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256';
    ssl_prefer_server_ciphers off;
    
    # HSTS
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    
    location / {
        proxy_pass http://backend:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

# Redirect HTTP to HTTPS
server {
    listen 80;
    server_name api.mockupaws.com;
    return 301 https://$server_name$request_uri;
}

🛡️ Rate Limiting Verification

Test Commands

# Test auth rate limiting (should block after 5 requests)
for i in {1..7}; do
    curl -X POST http://localhost:8000/api/v1/auth/login \
         -H "Content-Type: application/json" \
         -d '{"email":"test@test.com","password":"wrong"}' \
         -w "Status: %{http_code}\n" -o /dev/null -s
done
# Expected: First 5 = 401, 6th+ = 429

# Test general rate limiting (should block after 100 requests)
for i in {1..105}; do
    curl http://localhost:8000/health \
         -w "Status: %{http_code}\n" -o /dev/null -s
done
# Expected: First 100 = 200, 101st+ = 429

Checklist

  • Auth endpoints return 429 after 5 failed attempts
  • Rate limit headers are present in responses
  • Rate limits reset after time window
  • Different limits for different endpoint types
  • Burst allowance for legitimate traffic

🔑 JWT Security Verification

Secret Generation

# Generate a secure JWT secret
openssl rand -hex 32

# Example output:
# a3f5c8e9d2b1f4a7c6e8d9b0a2c4e6f8a1b3d5c7e9f2a4b6c8d0e2f4a6b8c0d

# Verify length (should be 64 hex chars = 32 bytes)
openssl rand -hex 32 | wc -c
# Expected: 65 (64 chars + newline)

Token Validation Tests

# 1. Test valid token
curl http://localhost:8000/api/v1/auth/me \
     -H "Authorization: Bearer <valid_token>"
# Expected: 200 with user data

# 2. Test expired token
curl http://localhost:8000/api/v1/auth/me \
     -H "Authorization: Bearer <expired_token>"
# Expected: 401 {"error": "token_expired"}

# 3. Test invalid signature
curl http://localhost:8000/api/v1/auth/me \
     -H "Authorization: Bearer invalid.token.here"
# Expected: 401 {"error": "invalid_token"}

# 4. Test missing token
curl http://localhost:8000/api/v1/auth/me
# Expected: 401 {"error": "missing_token"}

Checklist

  • JWT secret is ≥32 characters
  • Access tokens expire in 30 minutes
  • Refresh tokens expire in 7 days
  • Token rotation is implemented
  • Expired tokens are rejected
  • Invalid signatures are rejected
  • Token payload doesn't contain sensitive data

🗝️ API Keys Validation

Creation Flow Test

# 1. Create API key
curl -X POST http://localhost:8000/api/v1/api-keys \
     -H "Authorization: Bearer <jwt_token>" \
     -H "Content-Type: application/json" \
     -d '{
         "name": "Test Key",
         "scopes": ["read:scenarios"],
         "expires_days": 30
     }'
# Response should include: {"key": "mk_xxxx...", ...}
# ⚠️ Save this key - it won't be shown again!

# 2. List API keys (should NOT show full key)
curl http://localhost:8000/api/v1/api-keys \
     -H "Authorization: Bearer <jwt_token>"
# Response should show: prefix, name, scopes, but NOT full key

# 3. Use API key
curl http://localhost:8000/api/v1/scenarios \
     -H "X-API-Key: mk_xxxxxxxx..."
# Expected: 200 with scenarios list

# 4. Test revoked key
curl http://localhost:8000/api/v1/scenarios \
     -H "X-API-Key: <revoked_key>"
# Expected: 401 {"error": "invalid_api_key"}

Storage Verification

-- Connect to database
\c mockupaws

-- Verify API keys are hashed (not plaintext)
SELECT key_prefix, key_hash, LENGTH(key_hash) as hash_length 
FROM api_keys 
LIMIT 5;

-- Expected: key_hash should be 64 chars (SHA-256 hex)
-- Should NOT see anything like 'mk_' in key_hash column

Checklist

  • API keys use mk_ prefix
  • Full key shown only at creation
  • Keys are hashed (SHA-256) in database
  • Only prefix is stored plaintext
  • Scopes are validated on each request
  • Expired keys are rejected
  • Revoked keys return 401
  • Keys have associated user_id

📝 Input Validation Tests

SQL Injection Test

# Test SQL injection in scenario ID
curl "http://localhost:8000/api/v1/scenarios/1' OR '1'='1"
# Expected: 422 (validation error) or 404 (not found)
# Should NOT return data or server error

# Test in query parameters
curl "http://localhost:8000/api/v1/scenarios?name='; DROP TABLE users; --"
# Expected: 200 with empty list or validation error
# Should NOT execute the DROP statement

XSS Test

# Test XSS in scenario creation
curl -X POST http://localhost:8000/api/v1/scenarios \
     -H "Content-Type: application/json" \
     -d '{
         "name": "<script>alert(1)</script>",
         "region": "us-east-1"
     }'
# Expected: Script tags are escaped or rejected in response

Checklist

  • SQL injection attempts return errors (not data)
  • XSS payloads are escaped in responses
  • Input length limits are enforced
  • Special characters are handled safely
  • File uploads validate type and size

🔒 CORS Configuration

Test CORS Policy

# Test preflight request
curl -X OPTIONS http://localhost:8000/api/v1/scenarios \
     -H "Origin: http://localhost:5173" \
     -H "Access-Control-Request-Method: POST" \
     -H "Access-Control-Request-Headers: Content-Type,Authorization" \
     -v

# Expected response headers:
# Access-Control-Allow-Origin: http://localhost:5173
# Access-Control-Allow-Methods: GET, POST, PUT, DELETE
# Access-Control-Allow-Headers: Content-Type, Authorization

# Test disallowed origin
curl -X GET http://localhost:8000/api/v1/scenarios \
     -H "Origin: http://evil.com" \
     -v
# Expected: No Access-Control-Allow-Origin header (or 403)

Checklist

  • CORS only allows configured origins
  • Credentials header is set correctly
  • Preflight requests work for allowed origins
  • Disallowed origins are rejected
  • CORS headers are present on all responses

🚨 Security Headers

Verify Headers

curl -I http://localhost:8000/health

# Expected headers:
# X-Content-Type-Options: nosniff
# X-Frame-Options: DENY
# X-XSS-Protection: 1; mode=block
# Strict-Transport-Security: max-age=31536000; includeSubDomains

Checklist

  • X-Content-Type-Options: nosniff
  • X-Frame-Options: DENY
  • X-XSS-Protection: 1; mode=block
  • Strict-Transport-Security (in production)
  • Server header doesn't expose version

🗄️ Database Security

Connection Security

# Verify database uses SSL (production)
psql "postgresql://user:pass@host/db?sslmode=require"

# Check for SSL connection
SHOW ssl;
# Expected: on

User Permissions

-- Verify app user has limited permissions
\du app_user

-- Should have: CONNECT, USAGE, SELECT, INSERT, UPDATE, DELETE
-- Should NOT have: SUPERUSER, CREATEDB, CREATEROLE

Checklist

  • Database connections use SSL/TLS
  • Database user has minimal permissions
  • No default passwords in use
  • Database not exposed to public internet
  • Regular backups are encrypted

📊 Logging and Monitoring

Security Events to Log

Event Log Level Alert
Authentication failure WARNING After 5 consecutive
Rate limit exceeded WARNING After 10 violations
Invalid API key WARNING After 5 attempts
Suspicious pattern ERROR Immediate
Successful admin action INFO -

Checklist

  • Authentication failures are logged
  • Rate limit violations are logged
  • API key usage is logged
  • Sensitive data is NOT logged
  • Logs are stored securely
  • Log retention policy is defined

🧪 Final Verification Commands

Run this complete test suite:

#!/bin/bash
# security-tests.sh

BASE_URL="http://localhost:8000"
JWT_TOKEN="your-test-token"
API_KEY="your-test-api-key"

echo "=== Security Verification Tests ==="

# 1. HTTPS Redirect (production only)
echo "Testing HTTPS redirect..."
curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/health"

# 2. Rate Limiting
echo "Testing rate limiting..."
for i in {1..6}; do
    CODE=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/health")
    echo "Request $i: $CODE"
done

# 3. JWT Validation
echo "Testing JWT validation..."
curl -s "$BASE_URL/api/v1/auth/me" -H "Authorization: Bearer invalid"

# 4. API Key Security
echo "Testing API key validation..."
curl -s "$BASE_URL/api/v1/scenarios" -H "X-API-Key: invalid_key"

# 5. SQL Injection
echo "Testing SQL injection protection..."
curl -s "$BASE_URL/api/v1/scenarios/1%27%20OR%20%271%27%3D%271"

# 6. XSS Protection
echo "Testing XSS protection..."
curl -s -X POST "$BASE_URL/api/v1/scenarios" \
     -H "Content-Type: application/json" \
     -d '{"name":"<script>alert(1)</script>","region":"us-east-1"}'

echo "=== Tests Complete ==="

Sign-off

Role Name Date Signature
Security Lead
DevOps Lead
QA Lead
Product Owner

Post-Deployment

After deployment:

  • Verify all security headers in production
  • Test authentication flows in production
  • Verify API key generation works
  • Check rate limiting is active
  • Review security logs for anomalies
  • Schedule security review (90 days)

This checklist must be completed before any production deployment.
For questions, contact the security team.