PicPac Mobile Документы Открыть приложение

Как мы защищаем данные

Что защищено, чем и где это проверить

Коротко для жюри и проверяющих: что защищено, чем и где это можно проверить. Ограничения указаны в конце, они не скрываются.

Роли и права Шифрование Журнал действий ≈ 3 минуты чтения

Роли и права

  • Ролей две: клиент (customer) и сотрудник (operator). Внутри выпускного альбома есть организатор и участник.
  • Права проверяет только сервер. Приложение на экране роль показывает, но границей безопасности не является: на каждом запросе API проверяет роль и принадлежность объекта.
  • Чужой объект возвращает 404, а не 403: так не раскрывается, существует ли он. Каждый такой отказ пишется в журнал как access.denied.
  • Сотрудник видит заказы, обращения и журнал. Каталога, корзины и AI в его разделе нет.

Проверка: api/test/operator.test.ts, api/test/albums.test.ts, api/test/orders.test.ts.

Вход и пароли

  • Код входа хранится только в виде HMAC-хеша и действует ограниченное время. Приглашения в альбом хранятся как хеш токена: утечка таблицы не даёт доступа к альбомам.
  • Лимиты: 5 неверных кодов и 3 запроса кода за 10 минут на контакт; 5 неверных паролей альбома за 10 минут на приглашение и пользователя. Дальше 429 TOO_MANY_ATTEMPTS. Телефон или почта в журнал открытым текстом не попадают.
  • Пароль выпускного альбома (4–64 символа) хранится как scrypt с солью, не логируется и не отдаётся в API. Чтобы вступить в альбом, нужны и ссылка-приглашение, и пароль: утечка ссылки не открывает фото детей.

Проверка: api/test/auth.test.ts («лимиты входа»), api/test/albums.test.ts («пароль альбома»).

Фото и ссылки

  • Фото отдаются по подписанной ссылке (HMAC), которая действует один час; испорченная или просроченная ссылка не открывается.
  • Участник альбома видит и правит только свои фото; организатор видит все.
  • Ответы API не кэшируются (Cache-Control: no-store), на всех ответах X-Content-Type-Options: nosniff и Referrer-Policy: no-referrer; Caddy добавляет Strict-Transport-Security. Доступ к сайту и API только по HTTPS.

Журнал действий

Таблица audit_log только дополняется: пользователь, время, действие, объект, результат. Сотрудник видит журнал в своём разделе. Журнал переживает удаление пользователя, но содержит только идентификаторы, а не содержимое данных.

AI и согласие

  • Фото уходит во внешний сервис обработки (aiai.by) только после явного согласия пользователя и только для той правки, которую он запустил.
  • Согласие можно отозвать в профиле («Мои данные и безопасность»): после этого AI снова просит согласие.
  • К запросам применяется фильтр недопустимых инструкций; результат обработки не попадает в заказ без действия пользователя. Лимит: не больше 10 обработок в час на пользователя.

Удаление данных

В профиле: «Мои данные и безопасность» показывает, сколько проектов, фото и заказов хранится, и позволяет удалить всё. Удаляются проекты, фото (вместе с файлами), AI-задачи и согласия; заказы остаются в истории без привязки к человеку. Проверка: api/test/privacy.test.ts.

Данные в репозитории

Только синтетические данные. Секреты (JWT_SECRET, FILE_URL_SECRET, ключ aiai.by, пароль базы) лежат в .env на сервере, в репозитории только .env.example без значений.

Ограничения

  • Демо-режим (DEMO_MODE=true): код входа всегда 000000. Он включён на демо-сервере, чтобы жюри могло войти без SMS; для настоящих пользователей его нужно выключить. Лимиты попыток при этом работают, а демо-код остаётся рабочим.
  • Коды входа не отправляются по SMS и почте: до продакшена нужен провайдер рассылки.
  • Фото хранятся на локальном диске сервера; для нескольких серверов нужно объектное хранилище.
  • Права проверяются в коде API, политик на уровне базы (RLS) нет.
  • Платежи имитируются, платёжных данных в системе нет.

Исходник страницы — SECURITY.md в репозитории проекта.

SECURITY.md