Версия:
3.3.51
Обновлено:
2026-01-23
Матрица контролей безопасности
1. Контроли аутентификации
| ID |
Контроль |
Реализация |
Файлы |
Покрытие тестами |
| AUTH-001 |
Валидация JWT токена |
Верификация подписи HS256 |
backend/shared/http/jwt_validator.go |
Интеграционные |
| AUTH-002 |
Expiration токена |
24-часовое время жизни с exp claim |
backend/auth/service/jwt_mvp.go |
Unit |
| AUTH-003 |
Валидация Issuer |
Проверка iss claim соответствует конфигу |
jwt_validator.go:ValidateToken() |
Интеграционные |
| AUTH-004 |
Верификация Supabase JWT |
JWKS валидация для токенов Supabase |
backend/auth/service/supabase_auth.go |
Интеграционные |
| AUTH-005 |
Ограничение тестовых токенов |
Тестовые токены только в development |
auth_middleware.go:handleTestToken() |
Unit |
| AUTH-006 |
Извлечение Bearer токена |
Стандартный парсинг Authorization header |
auth_utils.go:ExtractBearerToken() |
Unit |
AUTH-001: Валидация JWT токена
// backend/shared/http/jwt_validator.go
func (v *JWTValidator) ValidateToken(tokenString string) (*jwt.Token, error) {
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
// Проверка метода подписи HS256
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return []byte(cfg.GetJWTSecret()), nil
})
// ...
}
2. Контроли авторизации
| ID |
Контроль |
Реализация |
Файлы |
Покрытие тестами |
| AUTHZ-001 |
Ролевой доступ |
Раздельные типы токенов Admin vs User |
admin_auth_middleware.go, auth_middleware.go |
Интеграционные |
| AUTHZ-002 |
Whitelist админов |
Проверка админов через конфиг |
config/auth.yaml, IsAdmin() |
Unit |
| AUTHZ-003 |
Защита endpoints |
Middleware на защищённых маршрутах |
backend/shared/routing/*_router.go |
E2E |
| AUTHZ-004 |
Скоупинг пользователя |
JWT user_id для доступа к данным |
Все методы сервисов |
Интеграционные |
| AUTHZ-005 |
Проверка permissions |
Гранулярная валидация прав |
permissions_middleware.go |
Unit |
AUTHZ-002: Whitelist админов
# config/auth.yaml
admins:
- email: "admin@saga.fund"
permissions:
- "approve_withdrawals"
- "view_all_users"
// Проверка в middleware
if !cfg.IsAdmin(adminEmail) {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
3. Контроли валидации входных данных
| ID |
Контроль |
Реализация |
Файлы |
Покрытие тестами |
| INPUT-001 |
Валидация структур |
go-playground/validator теги |
Все request structs |
Unit |
| INPUT-002 |
Ethereum адреса |
Regex + go-ethereum валидация |
Handlers выводов |
Unit |
| INPUT-003 |
Валидация сумм |
Положительные, ненулевые, max лимиты |
Финансовые handlers |
Интеграционные |
| INPUT-004 |
Санитизация HTML |
bluemonday policy |
Handlers пользовательского ввода |
Unit |
| INPUT-005 |
Лимит размера запроса |
Max body size middleware |
request_size_middleware.go |
Unit |
type CreateWithdrawalRequest struct {
Amount decimal.Decimal `json:"amount" validate:"required,gt=0"`
ToAddress string `json:"to_address" validate:"required,eth_addr"`
Currency string `json:"currency" validate:"required,oneof=USDC USDT"`
Note string `json:"note" validate:"max=500"`
}
// Валидация в handler
if err := validator.Validate(req); err != nil {
return ValidationError(err)
}
-- Constraint в базе данных
CONSTRAINT valid_ethereum_address CHECK (
to_address ~ '^0x[a-fA-F0-9]{40}$'
)
4. Контроли Rate Limiting
| ID |
Контроль |
Реализация |
Файлы |
Покрытие тестами |
| RATE-001 |
Финансовые endpoints |
5 req/мин token bucket |
rate_limiting_middleware.go |
E2E |
| RATE-002 |
Auth endpoints |
20 req/мин token bucket |
rate_limiting_middleware.go |
E2E |
| RATE-003 |
Общие endpoints |
100 req/мин token bucket |
rate_limiting_middleware.go |
E2E |
| RATE-004 |
Отслеживание по IP |
Извлечение X-Forwarded-For |
rate_limit_components.go |
Unit |
| RATE-005 |
Rate Limit headers |
X-RateLimit-* в ответах |
rate_limiting_middleware.go |
E2E |
| RATE-006 |
Whitelist путей |
Health, static files исключены |
rate_limiting_middleware.go |
Unit |
RATE-001: Защита финансовых endpoints
// Пути под финансовым rate limiter (5 req/мин)
financialPaths := []string{
"/api/user/investments",
"/api/user/withdrawals",
"/api/user/blockchain/deposit",
"/api/admin/withdrawals",
}
| ID |
Контроль |
Реализация |
Файлы |
Покрытие тестами |
| HDR-001 |
Content-Security-Policy |
Ограничительный CSP |
csp.go, security_headers_middleware.go |
E2E |
| HDR-002 |
X-Frame-Options |
DENY |
security_headers_middleware.go |
Unit |
| HDR-003 |
X-Content-Type-Options |
nosniff |
security_headers_middleware.go |
Unit |
| HDR-004 |
Referrer-Policy |
strict-origin-when-cross-origin |
security_headers_middleware.go |
Unit |
| HDR-005 |
Permissions-Policy |
Отключение camera/mic/geo |
security_headers_middleware.go |
Unit |
| HDR-006 |
HSTS |
max-age=31536000 (только prod) |
security_headers_middleware.go |
Интеграционные |
| HDR-007 |
CORS |
Валидация whitelist origins |
security_headers_middleware.go |
E2E |
HDR-001: Content Security Policy
// backend/shared/middleware/csp.go
func BuildCSP(isDevelopment bool) string {
return strings.Join([]string{
"default-src 'self'",
"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://accounts.google.com",
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data: https:",
"connect-src 'self' https://*.supabase.co wss://*.supabase.co",
"frame-src 'self' https://accounts.google.com",
}, "; ")
}
6. Контроли защиты данных
| ID |
Контроль |
Реализация |
Файлы |
Покрытие тестами |
| DATA-001 |
TLS шифрование |
NGINX TLS 1.3 терминация |
nginx.conf |
Ручная проверка |
| DATA-002 |
HSTS enforcement |
Strict-Transport-Security |
security_headers_middleware.go |
E2E |
| DATA-003 |
Параметризованные запросы |
sqlx named queries |
Все repositories |
Code review |
| DATA-004 |
Исключение секретов из логов |
Структурированное логирование, без секретов |
Все вызовы логирования |
Code review |
| DATA-005 |
SafeDecimal |
Overflow-safe финансовая математика |
backend/shared/types/safedecimal.go |
Unit |
| DATA-006 |
Секреты в env |
.env файл, не в коде |
.env, config.go |
Code review |
DATA-003: Параметризованные запросы
// Все запросы используют именованные параметры - БЕЗ конкатенации строк
func (r *UserRepository) GetUserByEmail(ctx context.Context, email string) (*User, error) {
query := `SELECT * FROM users WHERE email = $1`
var user User
err := r.db.GetContext(ctx, &user, query, email)
return &user, err
}
DATA-005: SafeDecimal
// Без float64 для финансовых вычислений
type SafeDecimal struct {
decimal.Decimal
}
// Проверенная арифметика
func (s SafeDecimal) Add(other SafeDecimal) SafeDecimal {
return SafeDecimal{s.Decimal.Add(other.Decimal)}
}
7. Финансовые контроли
| ID |
Контроль |
Реализация |
Файлы |
Покрытие тестами |
| FIN-001 |
Валидация баланса |
Проверка перед выводом |
withdrawal_service.go |
Интеграционные |
| FIN-002 |
Атомарные транзакции |
DB транзакция + append-only |
withdrawal_service.go |
Интеграционные |
| FIN-003 |
Одобрение админа |
Многоэтапный workflow |
withdrawal_admin_service.go |
Интеграционные |
| FIN-004 |
Fordefi Multi-sig |
Внешнее custody одобрение |
Fordefi интеграция |
Ручная проверка |
| FIN-005 |
Min/Max лимиты |
Настраиваемые лимиты |
config/limits.yaml |
Unit |
| FIN-006 |
Immutable Audit Log |
Append-only транзакции |
таблица transactions |
Интеграционные |
FIN-002: Атомарность финансовых операций
Saga использует append-only архитектуру — баланс не хранится в отдельной таблице, а вычисляется по транзакциям:
-- Расчёт available balance (не UPDATE, а SELECT)
SELECT
COALESCE(SUM(CASE WHEN type = 'deposit' AND status = 'completed' THEN amount ELSE 0 END), 0)
- COALESCE(SUM(CASE WHEN type = 'withdrawal' AND status IN ('pending', 'completed') THEN amount ELSE 0 END), 0)
- COALESCE(SUM(CASE WHEN type = 'investment' AND status = 'completed' THEN amount ELSE 0 END), 0)
+ COALESCE(SUM(CASE WHEN type = 'reversal' THEN amount ELSE 0 END), 0)
AS available_balance
FROM transactions
WHERE user_id = $1;
// Атомарность через DB транзакцию при создании withdrawal
func (s *WithdrawalService) CreateWithdrawal(ctx context.Context, userID string, amount decimal.Decimal) error {
return s.db.WithTransaction(ctx, func(tx *sqlx.Tx) error {
// 1. Рассчитать текущий баланс
balance, err := s.balanceRepo.GetAvailableBalance(ctx, userID)
if err != nil {
return err
}
// 2. Проверить достаточность средств
if balance.LessThan(amount) {
return ErrInsufficientBalance
}
// 3. Создать withdrawal транзакцию (INSERT, не UPDATE)
return s.transactionRepo.Create(ctx, &Transaction{
UserID: userID,
Type: "withdrawal",
Amount: amount,
Status: "pending",
})
})
}
Преимущества append-only:
- Полный audit trail всех операций
- Невозможность "потерять" деньги через UPDATE
- Race conditions предотвращаются через DB transaction + расчёт в момент операции
8. Контроли безопасности Webhooks
| ID |
Контроль |
Реализация |
Файлы |
Покрытие тестами |
| HOOK-001 |
Верификация подписи |
HMAC валидация |
fordefi/webhook_handler.go |
Unit |
| HOOK-002 |
Валидация timestamp |
Защита от replay атак |
crypto2b/webhook_handler.go |
Unit |
| HOOK-003 |
Идемпотентность |
Обработка дублирующих событий |
Webhook handlers |
Интеграционные |
| HOOK-004 |
Только HTTPS |
TLS для webhook endpoints |
Конфиг NGINX |
Ручная проверка |
9. Контроли инфраструктуры
| ID |
Контроль |
Реализация |
Файлы |
Покрытие тестами |
| INFRA-001 |
Изоляция контейнера |
Docker с минимальным base |
Dockerfile |
Ручная проверка |
| INFRA-002 |
Blue-Green Deploy |
Zero-downtime с rollback |
scripts/deploy-*.sh |
Ручная проверка |
| INFRA-003 |
Health Checks |
/health endpoint мониторинг |
health_router.go |
Интеграционные |
| INFRA-004 |
Database TCP |
127.0.0.1 не socket |
.env, DB конфиг |
Ручная проверка |
| INFRA-005 |
Изоляция портов |
8080 внутренний, 443 внешний |
nginx.conf |
Ручная проверка |
10. Анализ пробелов в контролях
Реализовано, но можно усилить
| Контроль |
Текущее состояние |
Рекомендуемое улучшение |
| Отзыв токенов |
Нет blacklist |
Реализовать token blacklist |
| Admin MFA |
Не реализовано |
Добавить требование MFA |
| Ротация секретов |
Ручной процесс |
Автоматизированная ротация |
| Подпись запросов |
Не реализовано |
Подписывать финансовые запросы |
Не реализовано
| Контроль |
Риск |
Приоритет |
| WAF/DDoS защита |
ВЫСОКИЙ |
P1 |
| Сканирование секретов CI |
СРЕДНИЙ |
P2 |
| IP логирование транзакций |
НИЗКИЙ |
P3 |
| Token binding |
НИЗКИЙ |
P3 |
11. Сводка покрытия тестами
| Категория контролей |
Unit тесты |
Интеграционные |
E2E |
| Аутентификация |
✅ |
✅ |
✅ |
| Авторизация |
✅ |
✅ |
✅ |
| Валидация ввода |
✅ |
✅ |
Частично |
| Rate Limiting |
✅ |
- |
✅ |
| Security Headers |
✅ |
- |
✅ |
| Финансовые |
✅ |
✅ |
✅ |
| Webhooks |
✅ |
✅ |
- |
Связанные документы