WellNuo/AUDIT_REPORT.md
Sergei 671374da9a Improve BLE WiFi error handling and logging
- setWiFi() now throws detailed errors instead of returning false
- Shows specific error messages: "WiFi credentials rejected", timeout etc.
- Added logging throughout BLE WiFi configuration flow
- Fixed WiFi network deduplication (keeps strongest signal)
- Ignore "Operation cancelled" error (normal cleanup behavior)
- BatchSetupProgress shows actual error in hint field

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-26 19:10:45 -08:00

13 KiB
Raw Blame History

WellNuo Security & Quality Audit Report

Дата: 2026-01-22 Версия: 4.0 Последнее обновление: 2026-01-26


Резюме

Категория Кол-во Статус
Критичные (VULN-001 — VULN-008) 6 ВЫПОЛНЕНО — задеплоено 2026-01-26
🟢 Быстрые рекомендации 5 Можно сделать за 2-3 часа
🟡 Средние рекомендации ~15 1-3 дня на каждую
🔴 Большие задачи 3 1-2 недели (после релиза)
⏸️ Заблокированные 4 Ждём legacy backend

ВЫПОЛНЕНО — Критичные уязвимости

Задеплоено 2026-01-26. Code Review Score: 10/10. PRD: PRD-SECURITY.md

# Уязвимость Что сделано Файлы
1 VULN-001: Stripe Webhook Проверка STRIPE_WEBHOOK_SECRET на старте, сервер не запустится без него webhook.js, index.js
2 VULN-003: JWT Secret Проверка ≥32 символа на старте + обновлён secret до 64 символов index.js
3 VULN-004: OTP Rate Limit 5 попыток/15мин на verify, 3/15мин на send auth.js
4 VULN-005: Input Validation express-validator на всех POST/PATCH endpoints beneficiaries.js, stripe.js, invitations.js
5 VULN-007: Doppler Инструкция создана backend/DOPPLER_SETUP.md
6 VULN-008: npm audit Уязвимости в зависимостях исправлены package.json

⏸️ ЗАБЛОКИРОВАНО — Ждём legacy backend

Эти задачи зависят от изменений на eluxnetworks.net. Контакт: команда legacy backend.

Что ждём:

Phase 1 (ETA: mid next week):

  • set_deployment endpoint возвращает deployment_id в ответе

Phase 2 (post-MVP):

  • Header-based auth (Authorization: Bearer <token>)
  • beneficiary_password становится optional
  • external_beneficiary_id поле в таблице deployments

Заблокированные задачи:

Задача Проблема Когда разблокируется
FE-003: Legacy Credentials Hardcoded anandk / anandk_8 в api.ts:1444 Phase 2
LEGACY-001: Deployment ID set_deployment не возвращает ID Phase 1
LEGACY-002: Plaintext Passwords Отправляем пароль в открытом виде Phase 2
LEGACY-003: External ID Mapping Нет external_beneficiary_id в БД Phase 2

🟢 БЫСТРЫЕ РЕКОМЕНДАЦИИ (2-3 часа всего)

Простые фиксы, можно сделать перед релизом.

VULN-010: CORS Whitelist

Effort: 30 минут Файл: backend/src/index.js

Проблема: CORS разрешает запросы с любого домена.

Fix:

const corsOptions = {
  origin: ['https://wellnuo.smartlaunchhub.com', 'exp://'],
  credentials: true
};
app.use(cors(corsOptions));

VULN-012: Request Size Limit

Effort: 15 минут Файл: backend/src/index.js

Проблема: Нет лимита на размер body — можно отправить огромный JSON и положить сервер.

Fix:

app.use(express.json({ limit: '1mb' }));

FE-001: Stripe Key в Environment

Effort: 15 минут Файл: services/api.ts или где используется Stripe

Проблема: Stripe publishable key захардкожен.

Fix: Вынести в EXPO_PUBLIC_STRIPE_PUBLISHABLE_KEY.


FE-006: Убрать console.log в Production

Effort: 30 минут Файлы: babel.config.js, package.json

Проблема: Console.log попадают в production build.

Fix:

npm install babel-plugin-transform-remove-console --save-dev
// babel.config.js
module.exports = {
  presets: ['babel-preset-expo'],
  env: {
    production: {
      plugins: ['transform-remove-console']
    }
  }
};

FE-007: JWT Expiration Check

Effort: 1 час Файл: services/api.ts

Проблема: Если токен истёк — пользователь получает непонятные ошибки вместо редиректа на логин.

Fix:

function isTokenExpired(token) {
  try {
    const payload = JSON.parse(atob(token.split('.')[1]));
    return payload.exp * 1000 < Date.now();
  } catch {
    return true;
  }
}

// Перед каждым запросом
if (isTokenExpired(token)) {
  // Редирект на логин
}

🟡 СРЕДНИЕ РЕКОМЕНДАЦИИ (1-3 дня каждая)

Полезно, но не критично для релиза.

VULN-006: Логирование (Winston + Sentry)

Effort: 1 день Приоритет: Высокий после релиза

Что делаем:

  1. Winston для structured logs
  2. Sentry для алертов об ошибках
  3. Audit Trail таблица для истории действий
  4. Generic error messages в production (не показывать stack trace)

Почему важно: Сейчас если что-то падает — мы не узнаем. Sentry пришлёт алерт.


FE-004: SSL Pinning

Effort: 1 день Приоритет: Средний

Что делаем:

  1. Удалить app/(tabs)/bug.tsx (если есть)
  2. Добавить SSL pinning для API запросов
  3. Проверка URL в WebView

Почему важно: Защита от man-in-the-middle атак.


VULN-009: Admin 2FA

Effort: 2-3 дня Приоритет: Низкий (мало админов)

Что делаем: TOTP или email code для admin операций.


VULN-015: CSRF Protection

Effort: 1 день Приоритет: Низкий (мобильное приложение)

Что делаем: csurf middleware для web версии.


FE-010: SecureStore вместо AsyncStorage

Effort: 2-3 часа Приоритет: Средний

Что делаем: Перенести tokens из AsyncStorage в SecureStore (зашифрованное хранилище).


Effort: 2-3 часа Приоритет: Средний

Что делаем: Валидировать параметры deep links перед обработкой.


FE-019: Client-Side Rate Limiting

Effort: 1-2 часа Приоритет: Низкий

Что делаем: Debounce на кнопки отправки форм.


BUG-001 — BUG-005: Race Conditions & Memory Leaks

Effort: 1 день Приоритет: Средний

Баг Файл Проблема
BUG-001 AuthContext.tsx:44 Race condition в useEffect
BUG-002 BeneficiaryContext.tsx:59 Stale closure
BUG-003 api.ts:316 Silent auth failures
BUG-004 beneficiaries/[id]/index.tsx:146 Missing dependencies
BUG-005 beneficiaries/[id]/index.tsx:107 Interval not cleaned

Code Quality (SMELL-001 — SMELL-006)

Effort: 2-3 дня Приоритет: Низкий

  • Duplicate navigation logic
  • Magic numbers → constants
  • Mixed auth token types
  • Excessive any types (40+)
  • Callback hell → async/await
  • Silent fallbacks → add logging

🔴 БОЛЬШИЕ ЗАДАЧИ (1-2 недели, после релиза)

VULN-017: Refresh Tokens

Effort: 1 неделя (backend + frontend) Приоритет: После релиза

Сейчас: JWT живёт 7 дней, нет refresh.

Рекомендуется:

  • Access token: 15-60 минут
  • Refresh token: 7 дней
  • Автоматический refresh при истечении

Комментарий: Работает и так, но refresh tokens — best practice.


FE-017: Biometric Auth

Effort: 3-5 дней Приоритет: После релиза

Что делаем: Face ID / Touch ID для входа в приложение.

Комментарий: Nice to have, не критично для MVP.


RLS: Row Level Security

Effort: 1-2 недели Приоритет: После релиза

Что это: Защита данных на уровне базы данных. Даже если баг в коде — пользователь увидит только свои данные.

Подробный план: См. ЧАСТЬ 4 в конце этого документа.

Комментарий: Серьёзный рефакторинг. Делать когда будет время на полноценное тестирование.


📋 App Store Compliance

Требования для публикации в App Store.

Задача Статус Комментарий
PERMISSION-001: Camera description ⚠️ Проверить Нужно человеческое описание в app.json
PERMISSION-002: Microphone description ⚠️ Проверить Для голосового AI
DATA-001: Account deletion Нужно Apple требует возможность удалить аккаунт
PRIVACY-001: Privacy Policy URL ⚠️ Проверить Должен быть в app.json
PRIVACY-002: Privacy Manifest (iOS 17+) Нужно PrivacyInfo.xcprivacy файл
CONTENT-001: AI Chat Consent ⚠️ Проверить Согласие перед использованием AI

📊 Приоритеты

Перед релизом (опционально, 2-3 часа):

  1. VULN-010: CORS whitelist
  2. VULN-012: Request size limit
  3. FE-001: Stripe key в env
  4. FE-006: Remove console.log
  5. FE-007: JWT expiration check

Сразу после релиза:

  1. VULN-006: Winston + Sentry (мониторинг)
  2. DATA-001: Account deletion (требование Apple)
  3. BUG-001-005: Race conditions

Когда будет время:

  1. Refresh tokens
  2. Biometric auth
  3. RLS (Row Level Security)
  4. SSL Pinning

Ждём legacy backend:

  1. FE-003: Legacy credentials (Phase 2)
  2. LEGACY-001-003: Integration fixes (Phase 1/2)

ПРИЛОЖЕНИЕ: RLS (Row Level Security) — План реализации

Подробный план на случай если решим делать.

Что это и зачем

Сейчас: Проверки доступа в коде backend. Если баг — данные утекут.

С RLS: Защита на уровне БД. Даже при баге, SQL injection, или прямом доступе — пользователь увидит только свои данные.

Этапы

Этап Время Что делаем
1. Подготовка 2-3 часа Создать роль wellnuo_app, включить RLS
2. Политики 4-6 часов Создать policies для каждой таблицы
3. Query Builder 1-2 дня Переделать под RLS
4. Routes 2-3 дня Обновить все endpoints
5. Тесты 1 день Unit + интеграционные
6. Деплой 2-3 часа Миграция + проверка

Итого: 1-2 недели

Пример политики

-- Пользователь видит только своих beneficiaries
CREATE POLICY beneficiaries_select ON beneficiaries
  FOR SELECT
  USING (
    id IN (
      SELECT beneficiary_id FROM user_access
      WHERE accessor_id = current_setting('app.current_user_id', true)
    )
  );

Пример использования в коде

// До (без RLS)
const { data } = await supabase.from('beneficiaries').select('*');
const accessible = data.filter(b => hasAccess(userId, b.id)); // ручная фильтрация

// После (с RLS)
const db = createDb(userId); // привязка к пользователю
const { data } = await db.from('beneficiaries').select('*'); // RLS фильтрует автоматически

Файл: AUDIT_REPORT.md Обновлён: 2026-01-26