Инструкции

Аудит Leadera

Обзор проекта

Leadera — SaaS-система управления IT-ландшафтом с поддержкой диаграмм Ганта. Проект разделен на два компонента:

Бекенд

  • Стек: Go 1.21+, GIN, PostgreSQL 16+, pgx v5 + sqlx, JWT
  • Архитектура: Clean Architecture с разделением на слои
  • Особенности: RESTful API, автоматические миграции, система ролей через spaces

Фронтенд

  • Стек: Angular 21.1.3, Bootstrap 5, RxJS
  • Особенности: JWT-аутентификация, перехватчики HTTP, lazy loading

Бекенд — найденные проблемы

Критические проблемы

1. Уязвимость XSS в сериализации DOM

  • Файл: internal/handlers/space_handler.go:47-63
  • Критичность: critical
  • Описание: В методе GetSpaceMembers используется c.BindJSON(&req) без валидации, что может привести к XSS при сериализации данных в JSON
  • Рекомендация: Добавить валидацию DTO и использование HTML sanitizer

2. Небезопасное хранение токенов

  • Файл: internal/utils/password.go:19-21
  • Критичность: critical
  • Описание: Refresh токены хэшируются с помощью SHA256 вместо bcrypt, что делает их уязвимыми для перебора
  • Рекомендация: Перейти на bcrypt для хэширования refresh токенов

3. Отсутствие Rate Limiting

  • Файл: Нет реализации
  • Критичность: high
  • Описание: Нет ограничений на количество запросов к API, что делает систему уязвимой для brute-force атак
  • Рекомендация: Реализовать middleware для rate limiting

Высокие проблемы

4. Отсутствие валидации входных данных

  • Файл: internal/handlers/auth_handler.go:26-32, 52-58
  • Критичность: high
  • Описание: Нет строгой валидации email, длинны строк и других параметров запросов
  • Рекомендация: Внедрить библиотеку для валидации (go-playground/validator)

5. Отсутствие защиты от CSRF

  • Файл: Нет реализации
  • Критичность: high
  • Описание: Нет CSRF-токенов для POST/PUT/DELETE запросов
  • Рекомендация: Реализовать CSRF middleware

6. Потенциальные N+1 запросы

  • Файл: internal/repository/space_repository.go
  • Критичность: high
  • Описание: Нет индексов и оптимизации для запросов с JOIN при получении членов spaces
  • Рекомендация: Добавить правильные индексы и использовать eager loading

Средние проблемы

7. Отсутствие логирования ошибок

  • Файл: internal/handlers/gantt_handler.go:78-95
  • Критичность: medium
  • Описание: Ошибки валидации не логируются, что затрудняет отладку
  • Рекомендация: Структурированное логирование всех ошибок

8. Жестко закодированные настройки

  • Файл: internal/middleware/space_middleware.go:121-128
  • Критичность: medium
  • Описание: Статическая проверка subscription status без гибкой конфигурации
  • Рекомендация: Вынести в конфигурацию возможные статусы подписки

9. Отсутствие ограничений на количество записей

  • Файл: internal/handlers/gantt_handler.go
  • Критичность: medium
  • Описание: Нет ограничений на количество задач, разделов или диаграмм на пользователя
  • Рекомендация: Добавить лимиты через middleware

Низкие проблемы

10. Отсутствие валидации для special символов

  • Файл: internal/utils/validation.go:21-24
  • Критичность: low
  • Описание: Валидация паролей не включает некоторые специальные символы
  • Рекомендация: Расширить список разрешенных символов

11. Отсутствие Health Check для базы данных

  • Файл: internal/handlers/handler.go
  • Критичность: low
  • Описание: Health endpoint не проверяет доступность базы данных
  • Рекомендация: Добавить ping к базе данных в health check

Фронтенд — найденные проблемы

Критические проблемы

1. Хранение JWT токенов в localStorage

  • Файл: src/app/core/auth/auth.service.ts:25-40
  • Критичность: critical
  • Описание: Токены хранятся в localStorage, уязвимом для XSS атак
  • Рекомендация: Использовать HTTP-only cookies или secure storage

2. Отсутствие Content Security Policy (CSP)

  • Файл: src/index.html
  • Критичность: critical
  • Описание: Нет заголовков CSP для защиты от XSS
  • Рекомендация: Добавить заголовки CSP в HTTP ответы

Высокие проблемы

3. Нет валидации форм на стороне клиента

  • Файл: src/app/pages/auth/components/sign-up/sign-up.component.ts
  • Критичность: high
  • Описание: Формы не проходят полную валидацию перед отправкой
  • Рекомендация: Реализовать полноценную клиентскую валидацию

4. Отсутствие обработки race conditions

  • Файл: src/app/core/auth/auth.interceptor.ts:15-45
  • Критичность: high
  • Описание: Потенциальные race conditions при обновлении токенов
  • Рекомендация: Реализовать очередь запросов при обновлении токенов

5. Нет ограничений на длину вводимых данных

  • Файл: src/app/components/forms/gantt-form.component.ts
  • Критичность: high
  • Описание: Пользователь может вводить очень длинные тексты без ограничений
  • Рекомендация: Добавить максимальную длину для полей ввода

Средние проблемы

6. Нет proper error handling states

  • Файл: src/app/layouts/components/navbar/navbar.component.ts
  • Критичность: medium
  • Описание: Нет graceful handling ошибок при загрузке данных
  • Рекомендация: Реализовать skeleton loaders и error boundaries

7. Плохая производительность при большом количестве данных

  • Файл: src/app/pages/dashboard/gantt/gantt-page.component.ts
  • Критичность: medium
  • Описание: Нет virtual scrolling для больших списков задач
  • Рекомендация: Реализовать virtual scrolling и lazy loading

8. Отсутствие a11y для некоторых компонентов

  • Файл: src/app/components/charts/gantt-chart/gantt-chart.component.ts
  • Критичность: medium
  • Описание: Гант-диаграмма не имеет proper ARIA labels
  • Рекомендация: Добавить ARIA атрибуты и keyboard navigation

Низкие проблемы

9. Нет CSRF protection

  • Файл: src/app/core/auth/auth.interceptor.ts
  • Критичность: low
  • Описание: Отсутствие CSRF токенов для чувствительных операций
  • Рекомендация: Добавить CSRF токены в заголовки

10. Плохая мобильная адаптация

  • Файл: src/app/styles/gantt.scss
  • Критичность: low
  • Описание: Нет proper responsive design для мобильных устройств
  • Рекомендация: Добавить медиа-запросы и touch-friendly интерфейс

Безопасность

Обнаруженные уязвимости:

  1. XSS уязвимости - Отсутствие валидации входных данных на бэкенде
  2. Небезопасное хранение токенов - Refresh токены используют SHA256 вместо bcrypt
  3. Отсутствие rate limiting - Уязвимость для brute-force атак
  4. CSRF уязвимости - Отсутствие CSRF-токенов
  5. Storage vulnerabilities - localStorage используется для хранения JWT

Рекомендации по безопасности:

  1. Реализовать Input Validation на всех уровнях
  2. Перейти на HTTP-only cookies для токенов
  3. Реализовать rate limiting middleware
  4. Добавить CSRF protection
  5. Внедрить заголовки безопасности (CSP, HSTS, X-Frame-Options)
  6. Реализовать proper logging и мониторинг
  7. Добавить автоматические тесты безопасности

UX улучшения

Критические улучшения:

  1. Надежность аутентификации - Реализовать MFA
  2. Уведомления об ошибках - Лучшее error messaging
  3. Прогресс-бары - Для долгих операций

Высокие улучшения:

  1. Поиск по проекту - Быстрый поиск across spaces
  2. Drag & Drop - Для задач и диаграмм
  3. Keyboard shortcuts - Повышение продуктивности
  4. Темная тема - Улучшение UX при длительной работе

Средние улучшения:

  1. Экспорт данных -多种 форматы
  2. Коллаборация в реальном времени - WebSocket для live updates
  3. Шаблоны диаграмм - Pre-built templates
  4. Аналитика и отчеты - Insights по проектам

Низкие улучшения:

  1. Mobile app - iOS/Android приложения
  2. Интеграции - Slack, Teams, Jira и др.
  3. API для плагинов - Расширяемость системы

Приоритизированный план исправления

Приоритет Проблема Файлы Трудоёмкость
Critical XSS уязвимости internal/handlers/*.go 3 дня
Critical Хранение JWT в localStorage src/app/core/auth/*.ts 1 день
Critical Небезопасное хранение refresh токенов internal/utils/password.go 1 день
High Rate limiting middleware internal/middleware/ 2 дня
High CSRF protection internal/middleware/, src/app/core/auth/ 2 дня
High Валидация входных данных internal/handlers/, internal/utils/ 3 дня
Medium Оптимизация запросов БД internal/repository/ 2 дня
Medium Структурированное логирование internal/handlers/ 1 день
Low CSP заголовки src/index.html, конфигурация сервера 1 день
Low A11y улучшения src/app/components/ 3 дня

Общая оценка:

  • Critical issues: 6 задач, 8 дней
  • High issues: 5 задач, 7 дней
  • Medium issues: 3 задачи, 6 дней
  • Low issues: 4 задачи, 5 дней

Общая трудоёмкость: 26 дней разработки + 3 дня на тестирование = 29 дней

SSH туннели для VPS reverse proxy

Настройка SSH туннелей

VPS reg.ru (95.163.232.9)

# На Mac Studio: создать туннель для каждого сервиса
ssh -N -R 8080:localhost:8080 root@95.163.232.9    # leadera-api
ssh -N -R 8081:localhost:4096 root@95.163.232.9    # opencode
ssh -N -R 8082:localhost:4200 root@95.163.232.9    # leadera-fe
ssh -N -R 8083:localhost:8080 root@95.163.232.9    # docs-a2v

Настройка launchd plist

Файл: ~/Library/LaunchAgents/com.openclaw.sshtunnel.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.openclaw.sshtunnel</string>
    <key>ProgramArguments</key>
    <array>
        <string>ssh</string>
        <string>-N</string>
        <string>-R</string>
        <string>8080:localhost:8080</string>
        <string>root@95.163.232.9</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
</dict>
</plist>

Автозапуск

# Загрузить plist
launchctl load ~/Library/LaunchAgents/com.openclaw.sshtunnel.plist

# Проверить статус
launchctl list | grep sshtunnel

# Удалить (при необходимости)
launchctl unload ~/Library/LaunchAgents/com.openclaw.sshtunnel.plist

Доступ к сервисам

Через reverse proxy на VPS:

Настройка VPS как реверс-прокси

Общая схема

Mac Studio (локальная сеть)
    → autossh (SSH-туннели)
    → VPS 95.163.232.9 (Debian)
    → nginx (HTTPS reverse proxy)
    → интернет

Что нужно на VPS

1. Установленные пакеты

apt update
apt install nginx certbot python3-certbot-nginx

2. SSH-доступ

  • Авторизация только по ключам
  • Публичный ключ с Mac Studio добавлен в /root/.ssh/authorized_keys

3. nginx

Для каждого домена создать server block:

  • HTTP → редирект на HTTPS
  • HTTPS с SSL-сертификатом Let’s Encrypt
  • proxy_pass на localhost-порт туннеля

Пример структуры:

Подключение claw.a2v.space (OpenClaw)

Архитектура

Mac Studio (192.168.0.37:18789)
    → autossh SSH-туннель
    → VPS 95.163.232.9:8080
    → nginx HTTPS
    → https://claw.a2v.space

Шаги настройки

1. DNS

A-запись claw.a2v.space95.163.232.9

NS-серверы: ns1.hosting.reg.ru, ns2.hosting.reg.ru

2. Mac Studio — OpenClaw

  • Порт: 18789
  • Конфиг: ~/.openclaw/openclaw.json

3. SSH-туннель (launchd)

Plist: ~/Library/LaunchAgents/com.openclaw.sshtunnel.plist

Ключевой флаг: -R 8080:localhost:18789

4. VPS — nginx конфиг

server {
    listen 80;
    server_name claw.a2v.space;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    server_name claw.a2v.space;

    ssl_certificate /etc/letsencrypt/live/claw.a2v.space/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/claw.a2v.space/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

5. SSL-сертификат

certbot certonly --nginx -d claw.a2v.space

6. OpenClaw config

{
  "allowedOrigins": ["https://claw.a2v.space"],
  "trustedProxies": ["127.0.0.1"]
}

Подключение code.a2v.space (OpenCode)

Архитектура

Mac Studio (localhost:4096)
    → autossh SSH-туннель (-R 8081:localhost:4096)
    → VPS 95.163.232.9:8081
    → nginx HTTPS
    → https://code.a2v.space

Параметры

Параметр Значение
Локальный порт 4096
Туннель порт 8081
pm2 процесс opencode
SSL сертификат /etc/letsencrypt/live/code.a2v.space/

nginx конфиг

server {
    listen 80;
    server_name code.a2v.space;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    server_name code.a2v.space;

    ssl_certificate /etc/letsencrypt/live/code.a2v.space/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/code.a2v.space/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8081;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

SSL-сертификат

certbot certonly --nginx -d code.a2v.space

Подключение sand.a2v.space (Leadera Project)

Архитектура

Mac Studio
    ├─ Frontend (Angular) :4200 (pm2: leadera-fe)
    ├─ Backend (Go) :8080 (pm2: leadera-api)
    └─ PostgreSQL 16 в Docker (Colima, container: app-leadera-db)
        → autossh SSH-туннель (-R 8082:localhost:4200 -R 8083:localhost:8080)
    → VPS 95.163.232.9
    → nginx HTTPS
    → https://sand.a2v.space

Параметры

Компонент Локальный порт Туннель порт pm2 имя
Frontend (Angular) 4200 8082 leadera-fe
Backend (Go) 8080 8083 leadera-api

SSL сертификат: /etc/letsencrypt/live/sand.a2v.space/

nginx конфиг

server {
    listen 80;
    server_name sand.a2v.space;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    server_name sand.a2v.space;

    ssl_certificate /etc/letsencrypt/live/sand.a2v.space/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/sand.a2v.space/privkey.pem;

    location /api {
        proxy_pass http://127.0.0.1:8083;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location / {
        proxy_pass http://127.0.0.1:8082;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

База данных

PostgreSQL 16 в Docker через Colima: