Перейти к содержанию
Версия: 3.3.51 Обновлено: 2025-11-14

Security Architecture

Security Layers

Saga реализует defense-in-depth подход для Integration-Only архитектуры:

flowchart TB
    subgraph L1["Layer 1: Network Security"]
        N1["HTTPS/TLS 1.3"]
        N2["Firewall rules (UFW)"]
        N3["CORS policies"]
    end

    subgraph L2["Layer 2: Authentication"]
        A1["Supabase Auth (Email-first)"]
        A2["JWT tokens (HS256)"]
        A3["Admin/User role separation"]
    end

    subgraph L3["Layer 3: Application Security"]
        AP1["Input validation"]
        AP2["SQL parameterization"]
        AP3["Rate limiting"]
        AP4["CSRF protection"]
    end

    subgraph L4["Layer 4: Data Security"]
        D1["Encrypted connections"]
        D2["SafeDecimal for financial ops"]
        D3["Audit logging"]
    end

    subgraph L5["Layer 5: Enterprise Integration"]
        E1["Crypto2B API authentication"]
        E2["Fordefi webhook verification"]
        E3["MFA via Supabase"]
    end

    L1 --> L2
    L2 --> L3
    L3 --> L4
    L4 --> L5

    style L1 fill:#e3f2fd
    style L2 fill:#fff3e0
    style L3 fill:#e8f5e9
    style L4 fill:#fce4ec
    style L5 fill:#f3e5f5

🔑 Authentication System

JWT-Based Authentication

Architecture:

  • HS256 Algorithm: Symmetric signing with JWT_SECRET
  • Token Lifetime: 24 hours (configurable)
  • Refresh Strategy: Re-authentication через Supabase Auth
  • Storage: HttpOnly cookies (NOT localStorage)
  • ❌ NO WALLET DATA: JWT не содержит wallet_address

Token Structure (Email-First):

{
  "header": {
    "alg": "HS256",
    "typ": "JWT"
  },
  "payload": {
    "user_id": 123,
    "email": "user@example.com",
    "full_name": "John Doe",
    "exp": 1696665600,
    "iss": "saga-platform"
  },
  "signature": "..."
}

⚠️ ВАЖНО: В Integration-Only архитектуре JWT НЕ содержит wallet данных, только email и user metadata от Supabase Auth.

Admin Tokens vs User Tokens:

// Admin JWT claims (elevated permissions)
type AdminClaims struct {
    jwt.StandardClaims
    Email       string   `json:"email"`
    Permissions []string `json:"permissions"`
    Roles       []string `json:"roles"`
}

// User JWT claims (standard access, Integration-Only)
type JWTClaims struct {
    jwt.StandardClaims
    UserID      int64  `json:"user_id"`
    Email       string `json:"email"`
    FullName    string `json:"full_name,omitempty"`
    // ❌ НЕТ WalletAddr архитектура
}

Supabase Email-First Authentication

Authentication Flow:

1. User выбирает метод: Google OAuth / Email+Password / Magic Link
2. Supabase Auth обрабатывает аутентификацию
3. Frontend получает Supabase JWT token
4. Backend валидирует Supabase JWT через JWKS
5. Backend выдает собственный JWT token (БЕЗ wallet данных)

Implementation:

// Frontend: Supabase Auth
import { createClient } from '@supabase/supabase-js'

// 1. Google OAuth
const { data, error } = await supabase.auth.signInWithOAuth({
  provider: 'google'
});

// 2. Email/Password
const { data, error } = await supabase.auth.signInWithPassword({
  email: 'user@example.com',
  password: 'password'
});

// 3. Magic Link
const { data, error } = await supabase.auth.signInWithOtp({
  email: 'user@example.com'
});

Backend Validation:

// Валидация Supabase JWT через JWKS
func validateSupabaseJWT(token string) (*SupabaseUserInfo, error) {
    // Получить JWKS от Supabase
    jwks, err := getSupabaseJWKS()

    // Валидировать JWT signature
    claims, err := jwt.ParseWithClaims(token, &SupabaseClaims{}, func(token *jwt.Token) (interface{}, error) {
        return jwks.GetKey(token.Header["kid"].(string))
    })

    if err != nil {
        return nil, err
    }

    // Создать internal JWT (БЕЗ wallet_address)
    internalJWT := createInternalJWT(claims.Email, claims.UserID, claims.FullName)
    return &SupabaseUserInfo{
        Email: claims.Email,
        FullName: claims.FullName,
        InternalToken: internalJWT,
    }, nil
}

⚠️ КРИТИЧНО: Никаких wallet signatures, только email-based аутентификация!

Authorization System

Role-Based Access Control (RBAC)

Roles:

  • Admin: Full platform access (config-defined emails)
  • User: Standard user access (registered users)
  • Anonymous: Public endpoints only

Permission Checks:

// Middleware для admin endpoints
func AdminAuthMiddleware(cfg *config.UnifiedConfig) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            // Extract JWT token
            token := extractTokenFromHeader(r)

            // Validate admin token
            claims, err := validator.ValidateAdminToken(token)
            if err != nil {
                http.Error(w, "Unauthorized", http.StatusUnauthorized)
                return
            }

            // Check admin email
            if !cfg.IsAdminEmail(claims.Email) {
                http.Error(w, "Forbidden", http.StatusForbidden)
                return
            }

            next.ServeHTTP(w, r)
        })
    }
}

Endpoint Protection

Public Endpoints (no auth required):

  • /health
  • /api/blockchain/networks

User Endpoints (JWT required):

  • /api/user/balance
  • /api/user/transactions

Admin Endpoints (Admin JWT required):

  • /api/admin/users
  • /api/admin/withdrawals/*
  • /api/admin/dashboard

Data Security

Database Security

Connection Security:

// Always use parameterized queries
row := db.QueryRow(
    "SELECT * FROM users WHERE email = $1",
    email, // Parameterized - prevents SQL injection
)

// NEVER use string concatenation
// BAD: query := "SELECT * FROM users WHERE email = '" + email + "'"

Password Storage:

// Passwords hashed with bcrypt
hashedPassword, err := bcrypt.GenerateFromPassword(
    []byte(password),
    bcrypt.DefaultCost,
)

// Verification
err = bcrypt.CompareHashAndPassword(
    hashedPassword,
    []byte(providedPassword),
)

Sensitive Data:

  • ✅ JWT secrets in environment variables
  • ✅ Database passwords in .env (NOT in code)
  • ✅ Private keys in secure key management
  • ❌ NO sensitive data in logs
  • ❌ NO secrets in git repository

Financial Data Security

SafeDecimal Architecture:

// All financial amounts use SafeDecimal
type SafeDecimal struct {
    value decimal.Decimal
}

// Prevents:
// - Float precision errors
// - Overflow/underflow
// - Rounding errors in financial calculations

Transaction Integrity:

// Database transactions for financial operations
tx, err := db.BeginTx(ctx, nil)
defer tx.Rollback() // Rollback on error

// 1. Debit from source
// 2. Credit to destination
// 3. Record transaction

tx.Commit() // Atomic commit

Network Security

TLS/HTTPS

Production Configuration:

# Nginx configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

Let's Encrypt Certificates:

# Certificate renewal (automatic)
certbot renew --nginx

# Check certificate status
certbot certificates

CORS Configuration

config.yaml:

cors:
  allowed_origins:
    - "https://app.saga.surf"
    - "https://admin.saga.surf"
    - "https://saga.surf"
  allowed_methods:
    - "GET"
    - "POST"
    - "PUT"
    - "DELETE"
  allowed_headers:
    - "Content-Type"
    - "Authorization"

Implementation:

// Chi CORS middleware
cors := cors.New(cors.Options{
    AllowedOrigins:   cfg.GetCORSAllowedOrigins(),
    AllowedMethods:   cfg.GetCORSAllowedMethods(),
    AllowedHeaders:   cfg.GetCORSAllowedHeaders(),
    AllowCredentials: true,
    MaxAge:           300,
})

router.Use(cors.Handler)

Firewall Rules

VPS Firewall (UFW):

# Allowed ports
ufw allow 22/tcp    # SSH
ufw allow 80/tcp    # HTTP (redirect to HTTPS)
ufw allow 443/tcp   # HTTPS
ufw allow 8545/tcp  # Blockchain RPC

# Denied by default
ufw default deny incoming
ufw default allow outgoing

# Enable firewall
ufw enable

🚫 Attack Prevention

SQL Injection Prevention

Always use parameterized queries:

// ✅ SAFE - Parameterized
db.Query("SELECT * FROM users WHERE email = $1", email)

// ❌ DANGEROUS - String concatenation
db.Query("SELECT * FROM users WHERE email = '" + email + "'")

XSS Prevention

Content Security Policy:

// Set CSP headers
w.Header().Set("Content-Security-Policy",
    "default-src 'self'; " +
    "script-src 'self' 'unsafe-inline'; " +
    "style-src 'self' 'unsafe-inline';")

Input Sanitization:

import "html"

// Escape user input before rendering
safeInput := html.EscapeString(userInput)

CSRF Protection

Token-based CSRF:

// Generate CSRF token
csrfToken := generateSecureToken()
session.Set("csrf_token", csrfToken)

// Validate on POST
if r.FormValue("csrf_token") != session.Get("csrf_token") {
    return errors.New("invalid CSRF token")
}

Rate Limiting

API Rate Limiting:

// Chi rate limiter middleware
rateLimiter := httprate.LimitByIP(
    100,                    // 100 requests
    1*time.Minute,         // per minute
)

router.Use(rateLimiter)

Security Monitoring

Audit Logging

Critical Operations Logged:

logger.InfoStructured("Admin action",
    "action", "approve_withdrawal",
    "admin_email", adminEmail,
    "withdrawal_id", withdrawalID,
    "amount", amount.String(),
    "timestamp", time.Now().UTC(),
)

Log Storage:

  • ✅ Structured logging (slog)
  • ✅ UTC timestamps
  • ✅ Immutable log files
  • ✅ Regular log rotation

Security Events

Events to Monitor:

  • Failed login attempts
  • Admin actions (withdrawals, user modifications)
  • Large financial transactions
  • Rate limit violations

Core Security:

Security Vulnerability Reports:

Security Best Practices

Development

  • ✅ Use environment variables for secrets
  • ✅ Parameterized SQL queries only
  • ✅ Input validation on all endpoints
  • ✅ HTTPS in production
  • ✅ Regular dependency updates

Deployment

  • ✅ TLS/HTTPS only
  • ✅ Strong JWT secrets (32+ characters)
  • ✅ Firewall rules configured
  • ✅ Regular security audits
  • ✅ Monitoring and alerting

Smart Contracts

  • ✅ OpenZeppelin audited libraries
  • ✅ Access control on critical functions
  • ✅ Reentrancy guards
  • ✅ Thorough testing
  • ✅ Third-party audits before mainnet