Инструкции
Аудит 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 интерфейс
Безопасность
Обнаруженные уязвимости:
- XSS уязвимости - Отсутствие валидации входных данных на бэкенде
- Небезопасное хранение токенов - Refresh токены используют SHA256 вместо bcrypt
- Отсутствие rate limiting - Уязвимость для brute-force атак
- CSRF уязвимости - Отсутствие CSRF-токенов
- Storage vulnerabilities - localStorage используется для хранения JWT
Рекомендации по безопасности:
- Реализовать Input Validation на всех уровнях
- Перейти на HTTP-only cookies для токенов
- Реализовать rate limiting middleware
- Добавить CSRF protection
- Внедрить заголовки безопасности (CSP, HSTS, X-Frame-Options)
- Реализовать proper logging и мониторинг
- Добавить автоматические тесты безопасности
UX улучшения
Критические улучшения:
- Надежность аутентификации - Реализовать MFA
- Уведомления об ошибках - Лучшее error messaging
- Прогресс-бары - Для долгих операций
Высокие улучшения:
- Поиск по проекту - Быстрый поиск across spaces
- Drag & Drop - Для задач и диаграмм
- Keyboard shortcuts - Повышение продуктивности
- Темная тема - Улучшение UX при длительной работе
Средние улучшения:
- Экспорт данных -多种 форматы
- Коллаборация в реальном времени - WebSocket для live updates
- Шаблоны диаграмм - Pre-built templates
- Аналитика и отчеты - Insights по проектам
Низкие улучшения:
- Mobile app - iOS/Android приложения
- Интеграции - Slack, Teams, Jira и др.
- 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.space → 95.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: