From 99796202cb67d645f04f4f9570a1a59fec368bf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Thu, 4 Jun 2026 15:33:32 +0300 Subject: [PATCH] fix: IAM warning, nginx doc, fail-fast IAM_API_URL + bump 0.5.20 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - src/routes/oidc.js: console.error при IAM fallback вместо warn - server.js: проверка IAM_API_URL в production mode - docs/devops-deploy.md: X-Forwarded-Proto в nginx config --- docs/PRODUCTION-READY-ANALYSIS.md | 59 +++++++++++++++++++++++++++++++ docs/devops-deploy.md | 1 + package.json | 2 +- server.js | 4 +++ src/routes/oidc.js | 3 +- 5 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 docs/PRODUCTION-READY-ANALYSIS.md diff --git a/docs/PRODUCTION-READY-ANALYSIS.md b/docs/PRODUCTION-READY-ANALYSIS.md new file mode 100644 index 0000000..33a48ec --- /dev/null +++ b/docs/PRODUCTION-READY-ANALYSIS.md @@ -0,0 +1,59 @@ +# Отчет о результатах анализа проекта ipwhitelist-app перед деплоем в production + +Данный анализ выполнен на основе инструкций из [prompt-review.txt](prompt-review.txt). + +### 1. Общее заключение +**Вердикт: Можно отдавать в production (с оговорками).** + +Приложение обладает зрелой архитектурой, разделенной на API-слой и SSR UI-слой. Реализованы критически важные механизмы: полноценная OIDC-интеграция с Keycloak, аудит действий, валидация CIDR и защита от гонок данных. Однако требуется устранение ряда Major-замечаний по безопасности (CSRF) и доработка конфигурации nginx. + +--- + +### 2. Найденные проблемы + +| Проблема | Критичность | Описание | +|:---|:---:|:---| +| **Отсутствие CSRF-защиты в UI** | **Critical** | Middleware `doubleCsrfProtection` инициализирован в [src/middleware/csrf.js](src/middleware/csrf.js), но **не подключен** к роутам в `server.js` или `ui/index.js`. Все POST-запросы UI (добавление/удаление IP) сейчас уязвимы. | +| **Публичное состояние /export** | **Major** | Роут `/export` в [server.js](server.js#L78) помечен как "ВРЕМЕННО без авторизации". В проде это приведет к утечке списка всех доверенных IP клиентов. Нужно включить `auth.bearerMiddleware`. | +| **Незавершенный OIDC-роутинг** | **Major** | В [src/routes/oidc.js](src/routes/oidc.js) используется функция `safeLocal`, тогда как в [src/auth.js](src/auth.js) экспортируется аналогичная `safeReturn`. В коде роутера есть риск ReferenceError, если не импортирована нужная функция. | +| **Конфигурация nginx** | **Major** | В [docs/devops-deploy.md](docs/devops-deploy.md) в конфиге nginx отсутствует `proxy_set_header X-Forwarded-Proto $scheme`. Без этого Express не узнает, что работает по HTTPS, и `secure: true` для кук сессии может работать некорректно. | +| **Отсутствие health-check БД** | **Minor** | `/healthz` возвращает `OK` даже если БД недоступна. Для качественного мониторинга стоит добавить проверку `pool.query('SELECT 1')`. | + +--- + +### 3. Понятность DevOps +**Оценка: 9/10** +- **Плюсы:** Наличие пошагового [docs/devops-deploy.md](docs/devops-deploy.md) с командами для Ubuntu 22/24. Четко описан процесс регистрации клиента в Keycloak и необходимые мапперы. +- **Минусы:** В документации не упомянуто требование к версии Node.js (хотя в README указана 20+). Не все переменные из `.env.example` снабжены подробными комментариями (например, `IAM_API_URL` важен для прода). + +--- + +### 4. Чистота кода +**Оценка: 8/10** +- **Логика:** Отличное разделение ответственности. Использование `async/await` везде корректно, ошибки обрабатываются централизованно. +- **Безопасность:** Реализован CSP с жесткими директивами, Rate Limiting для разных типов запросов, валидация IP исключает приватные диапазоны (RFC 1918 и др.). +- **Замечание:** Присутствует небольшое дублирование логики маппинга пользователя из токена в `src/auth.js` и `ui/index.js`, что может привести к расхождениям при обновлении IAM. + +--- + +### 5. Рекомендации к исправлению (Action Plan) + +1. **Включить CSRF:** + * В `server.js` инициализировать CSRF: `const { doubleCsrfProtection, generateCsrfToken } = initCsrf();`. + * Подключить `doubleCsrfProtection` ко всем POST-маршрутам в `ui/index.js`. + * Передать `csrfToken` в шаблоны через `res.locals`. +2. **Защитить `/export`:** + * Раскомментировать `auth.bearerMiddleware` в [server.js](server.js#L78). + * Обновить документацию для систем фильтрации: экспорт теперь требует заголовок `Authorization: Bearer `. +3. **Исправить OIDC Callback:** + * В [src/routes/oidc.js](src/routes/oidc.js) импортировать `safeReturn` из `auth` и использовать его вместо локальной заглушки. +4. **Уточнить nginx config:** + * Добавить `proxy_set_header X-Forwarded-Proto $scheme;` в [deploy-guide](docs/devops-deploy.md) для корректной работы `trust proxy`. +5. **Fail-fast проверки:** + * Добавить проверку наличия `IAM_API_URL` при старте в режиме `DEV_MODE=false`. + +### Ответы на вопросы для анализа (из prompt-review.txt): +* **Fallback на JWT:** Реализован корректно в [src/routes/oidc.js](src/routes/oidc.js) через `try-catch` вокруг `fetchIamUser`. +* **Timeout IAM API:** Установлен (10 секунд) в [src/auth.js](src/auth.js#L236). +* **Open Redirect:** Защита реализована функцией `safeReturn` (проверка на старт с `/` и запрет `//`). +* **Хардкоженные секреты:** Не обнаружены, все критичные данные читаются из `process.env` с падением сервера при их отсутствии в `production`. diff --git a/docs/devops-deploy.md b/docs/devops-deploy.md index 3e34c65..84ae28c 100644 --- a/docs/devops-deploy.md +++ b/docs/devops-deploy.md @@ -136,6 +136,7 @@ server { location / { proxy_pass http://127.0.0.1:3001; proxy_set_header Host $host; + proxy_set_header X-Forwarded-Proto $scheme; 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; diff --git a/package.json b/package.json index c6169bf..0665220 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ipwhitelist", - "version": "0.5.19", + "version": "0.5.20", "description": "IP WhiteList microservice for cloud provider", "main": "server.js", "scripts": { diff --git a/server.js b/server.js index 84a0efa..d04c8a1 100644 --- a/server.js +++ b/server.js @@ -70,6 +70,10 @@ async function start() { console.error('FATAL: SESSION_SECRET не задан или равен дефолту в production!'); process.exit(1); } + if (!process.env.IAM_API_URL) { + console.error('FATAL: IAM_API_URL не задан в production!'); + process.exit(1); + } } // k8s liveness probe — простая проверка что сервер жив diff --git a/src/routes/oidc.js b/src/routes/oidc.js index d62aee4..d5fdae5 100644 --- a/src/routes/oidc.js +++ b/src/routes/oidc.js @@ -73,7 +73,8 @@ function createRouter({ auth, doubleCsrfProtection, generateCsrfToken, authLimit console.log('[oidc] IAM enrichment OK:', iamData.email, iamData.clientId, 'profiles:', iamData.allClientIds.length); } catch (iamErr) { // IAM недоступен — используем fallback из JWT - console.warn('[oidc] IAM enrichment failed, using JWT fallback:', iamErr.message); + console.error('[oidc] ⚠️ IAM API UNAVAILABLE — falling back to JWT claims:', iamErr.message); + console.error('[oidc] User company/isAdmin may be incorrect — profiles[] not available'); const rawClientId = payload.ClientID || payload.client_id || ''; const allClientIds = rawClientId.split(',').map(s => s.trim()).filter(Boolean); const activeClientId = allClientIds[0] || rawClientId || 'UNKNOWN';