harden security and add public TLS scaffold
- require ADMIN_PASSWORD (no default), remove CORS - close public DB port, move DB credentials to .env (DB_PASSWORD) - fix HTML escaping, add helmet + sec headers (no CSP due to inline scripts) - rate limit public routes by IP (express-rate-limit) - validate restore data and confine file unlinking to uploads/ - block dangerous upload extensions, 30MB per-entry limit, SVG not served inline - return 400 on unknown group_id in POST /api/entries - add commented Caddy/Let's Encrypt reverse-proxy scaffold + Caddyfile.example - update README
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
- **Дашборд** — статистика, активные группы, активность за 14 дней, последние записи, топ воспитанников
|
||||
- **Резервное копирование** — экспорт/импорт полного дампа (БД + файлы) в `tar.gz`
|
||||
- **Настройки** — научные тексты футера, анти-спам интервал
|
||||
- **HTTPS** — самоподписанный TLS-сертификат, автогенерация при сборке
|
||||
- **HTTPS** — самоподписанный TLS-сертификат по умолчанию + готовая заготовка reverse-proxy (Caddy / Let's Encrypt) для публичного запуска
|
||||
|
||||
## Технологии
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
### Запуск
|
||||
|
||||
```bash
|
||||
# создайте .env с паролем администратора (см. раздел «Конфигурация»)
|
||||
# создайте .env с паролем администратора и БД (см. раздел «Конфигурация»)
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
@@ -38,7 +38,7 @@ docker compose up -d --build
|
||||
|
||||
- **HTTP** `http://localhost:3000` — редирект на HTTPS
|
||||
- **HTTPS** `https://localhost:3443` — приложение (самоподписанный сертификат, принимайте предупреждение браузера)
|
||||
- **PostgreSQL** `localhost:5432` — `app:app`, база `whereldo`
|
||||
- **PostgreSQL** — доступен только внутри docker-сети (порт 5432 наружу не публикуется)
|
||||
|
||||
Управление:
|
||||
|
||||
@@ -48,16 +48,26 @@ docker compose logs -f app
|
||||
docker compose down # остановка (данные сохраняются)
|
||||
```
|
||||
|
||||
> Приложение **не запустится** без `ADMIN_PASSWORD` (защита от пароля по умолчанию).
|
||||
> `DB_PASSWORD` задаёт пароль пользователя `app` в PostgreSQL.
|
||||
|
||||
## Конфигурация
|
||||
|
||||
Переменные окружения (`.env`):
|
||||
|
||||
| Переменная | По умолчанию | Назначение |
|
||||
|------------------|--------------|-------------------------------------|
|
||||
| `ADMIN_PASSWORD` | `admin` | Пароль администратора (X-Admin-Token) |
|
||||
| `DATABASE_URL` | см. compose | Строка подключения к PostgreSQL |
|
||||
| `ADMIN_PASSWORD` | — (обязательно) | Пароль администратора (X-Admin-Token). Без него сервер не стартует |
|
||||
| `DB_PASSWORD` | — (обязательно) | Пароль пользователя `app` в PostgreSQL |
|
||||
|
||||
Внутри контейнера `db` также задаются `POSTGRES_DB=whereldo`, `POSTGRES_USER=app`, `POSTGRES_PASSWORD=app`, `TZ=Europe/Moscow`.
|
||||
Пример `.env`:
|
||||
|
||||
```
|
||||
ADMIN_PASSWORD=сложный-пароль
|
||||
DB_PASSWORD=случайная-строка
|
||||
```
|
||||
|
||||
`DB_PASSWORD` подставляется в `docker-compose.yml` в `POSTGRES_PASSWORD` и `DATABASE_URL`. Если БД уже была инициализирована ранее, значение `DB_PASSWORD` должно совпадать с фактическим паролем пользователя `app` в БД (иначе приложение не подключится).
|
||||
|
||||
## Структура данных
|
||||
|
||||
@@ -89,6 +99,27 @@ docker compose down # остановка (данные сохраняютс
|
||||
./scripts/restore.sh # восстановление из архива
|
||||
```
|
||||
|
||||
## Безопасность
|
||||
|
||||
- **Пароль администратора** обязателен (`ADMIN_PASSWORD`); фолбэка на `admin` нет.
|
||||
- **CORS отключён** — кросс-доменные запросы к API запрещены.
|
||||
- **Rate limiting** по IP на публичные роуты: `POST /api/entries` — 10 запросов / 15 мин, загрузка файлов и share-ссылки — 300 / 15 мин.
|
||||
- **Загрузки** ограничены: 30 МБ суммарно на запись, 10 МБ на файл; заблокированы опасные расширения (`.html`, `.js`, `.svg`, `.xml`, `.exe` и др.); SVG иным способом не отдаётся inline.
|
||||
- **Restore** проходит полную валидацию данных бэкапа; удаление файлов ограничено каталогом `uploads/`.
|
||||
- **Заголовки**: `helmet` — `X-Frame-Options`, `nosniff`, HSTS, `Referrer-Policy`.
|
||||
- **Порт БД** 5432 наружу не публикуется (доступ только внутри docker-сети).
|
||||
- **TLS**: по умолчанию самоподписанный сертификат. Для публикации включите reverse-proxy Caddy с Let's Encrypt — заготовка закомментирована в `docker-compose.yml`, конфиг в `Caddyfile.example`.
|
||||
|
||||
### Публичный запуск (TLS)
|
||||
|
||||
```bash
|
||||
cp Caddyfile.example Caddyfile # подставить реальный домен
|
||||
# расскомментировать сервис caddy и перевести ports сервиса app в expose (следуйте комментариям в docker-compose.yml)
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
Caddy автоматически получит Let's Encrypt сертификат на 80/443.
|
||||
|
||||
## Основные API
|
||||
|
||||
| Метод | Путь | Назначение |
|
||||
@@ -113,8 +144,9 @@ docker compose down # остановка (данные сохраняютс
|
||||
## Структура проекта
|
||||
|
||||
```
|
||||
├── docker-compose.yml # сервисы app + db
|
||||
├── docker-compose.yml # сервисы app + db (+ закомментированный caddy)
|
||||
├── Dockerfile # сборка образа (Node 20, генерация TLS-сертификата)
|
||||
├── Caddyfile.example # шаблон reverse-proxy с Let's Encrypt (домен заменить)
|
||||
├── server.js # Express-приложение
|
||||
├── db/
|
||||
│ ├── init.sql # схема при первом запуске
|
||||
|
||||
Reference in New Issue
Block a user