Перейти к содержимому

Надёжность и безопасность магазина

TL;DR: Страница покрывает надёжность и безопасность магазина на уровне процессов: что можно кэшировать публично, а что содержит персональные цены и корзины, как защищать webhook-эндпоинты и восстанавливать резервные копии, как выглядит бизнес-мониторинг шире uptime. Базовые веб-меры (WAF, хардненинг, сканеры) описаны в разделе безопасности сайтов и здесь не дублируются.

Кэш ускоряет витрину, но смешивание кэша с персональным контентом выдаёт чужие данные другим пользователям. Правило разделения:

КонтентКэшировать публично (CDN/reverse proxy)Считать на сервере и не кэшировать
Каталог, карточки, баннерыДа—
Статические ассетыДа—
Остатки и ценыОсторожно: публично только если цены единые для всех; иначе — частично (etag, короткий TTL), остатки на сервереДа, если цены зависят от клиента или сегмента
КорзинаНикогдаДа
Личный кабинетНикогдаДа
Checkout любой шагНикогдаДа
Персональные цены, бонусыНикогдаДа

Простой ориентир: то, что одинаково у всех посетителей, может кэшироваться агрегатно; всё, что зависит от сессии, cookie, авторизации, сегмента клиента или группы (B2B), кэшированию не подлежит. Промежуточный вариант — кэшировать «каркас» страницы (шаблон, меню, категории), а персональные блоки (имя, бонусы, корзина) подгружать отдельным запросом.

Правильность разделения проверяет тест: один пользователь кладёт товар в корзину, второй открывает сайт из кэша — видеть чужой товар он не должен. Опасное место — reverse proxy и CDN: правило кэширования, описанное в документации, не всегда совпадает с фактическим заголовком Cache-Control от приложения.

HTTPS на всей витрине — базовое требование; выделение HTTPS только для checkout и кабинета недостаточно: cookie могут перехватываться на обычных страницах. Cookies сессий — Secure, HttpOnly, SameSite; конкретные требования уточняются профильным ревью.

Хранение секретов: ключи платёжных шлюзов и API учётных систем не в репозитории и не в общих документах. Хранилище секретов с ротацией; у каждого секрета указано, какая система или процесс его использует — иначе ротация ломает работающий интеграционный поток.

Роли и аудит: у админки магазина как минимум три роли, а не одна «админ»: работа с заказами (просмотр и статусы), работа с контентом (каталог и цены), управление доступами и настройками. Каждое значимое изменение (цена, остаток, статус заказа, выдача скидки, создание промокода) попадает в audit log: кто, что, когда, откуда (IP/сессия). Содержимое audit log нельзя редактировать через интерфейс администратора; при возможности он хранится отдельно от основной базы.

Бэкап магазина должен закрывать три класса данных: базу (заказы, клиенты, товары), файлы (карточки, контент, выгрузки для остатков и фидов) и конфигурацию (env, nginx, docker/podman определения). Расписание и полномасштабное восстановление с проверкой — см. операционную готовность. Минимум для магазина дополнительно:

  • Восстановление проверяется на копии prod, а не на пустом стенде: магазин нужно поднимать вместе с очередями и связями, а не только с файлами.
  • База данных и файловое хранилище восстанавливаются с согласованной точкой времени: заказ, оплаченный в 14:00, и его чек из базы — соседние данные; разрыв между ними чреват расхождениями в фискализации.
  • Допустимое окно потери данных (RPO) магазин выбирает по объёму ежедневных продаж: оно должно быть не больше, чем «продажи на N часов», которые бизнес готов повторно обработать вручную.

Webhook-и — эндпоинты, на которые внешние системы (платёжный шлюз, CRM, учётная система, логистика) присылают события о статусах. Два базовых требования:

  1. Подпись и аутентификация. Шлюз подписывает запрос секретом; сервер проверяет подпись, а если протокол подписи не предусматривает — ограничивает доступ по списку IP-адресов источника. Эндпоинт, принимающий любые запросы «как есть», открывает путь к фальшивым статусам «оплачено».
  2. Идемпотентность. Системы отсылают один и тот же webhook повторно при сомнении в доставке. Обработка должна сводить повторные запросы к одному результату: ключ идемпотентности — ID события или «ID заказа + статус»; повтор означает обновить, а не продублировать (второй чек, вторая отправка, двойное списание бонусов — типовые последствия дублирования).

Дополнительно: очередь приёма webhook — буфер пиков. Если шлюз шлёт всплеск событий, а учётная система занята, очередь хранит события без потери; потерянный webhook о «оплачено» разбирать дороже, чем хранить очередь.

Стандартный набор признаков: серия попыток оплатить одной картой, множественные неудачные оплаты с одного IP, заказ с самовывозом без личной верификации, необычно большая корзина у нового клиента, несоответствие имени держателя карты и получателя. Реализация в магазине: правила на уровне платёжного шлюза (обязательный 3-D Secure для рисковых сегментов, лимит операций по карте), ручная проверка подозрительных заказов перед отправкой, отдельная проверка контрагентов в B2B.

Антифрод всегда баланс между защитой и отсевом: слишком жёсткие правила теряют настоящих клиентов. Каждое правило блокировки обосновывается явно и периодически пересматривается, а не работает «навсегда».

Работа, которую система делает в момент заказа, разделяется на:

  • Синхронную дорогу (должна завершиться до ответа клиенту): создание заказа, резервирование остатка, запрос ссылки оплаты.
  • Асинхронные задачи (могут опоздать на минуты): email и уведомления, выгрузка в учёт, обновление фида, генерация чеков, передача в логистику.

Асинхронные задачи кладутся в очередь. Очередь спасает в пиках — письма не замедляют checkout — и в отказах: при недоступности учётной системы заказы накапливаются и обрабатываются, когда она поднимется. Обратная сторона: сама очередь становится наблюдаемым объектом (длина, возраст самой старой задачи, число повторных попыток) и входит в бизнес-мониторинг ниже.

Здоровье сайта (uptime, p95) покрывает вопрос «работает ли сайт». Бизнес-мониторинг отвечает на другой вопрос: «всё ли обработано, что должно быть обработано».

СигналНа что смотреть
Отставание остатковЗадержка выгрузки остатков из учётной системы в витрину; лимит (например, 30 минут — число условное)
Отставание ценЗадержка согласования цен между учётом и магазином
Необработанные заказыВозраст заказов без перехода в «обработан» после оплаты
Платёжные ошибкиДоля failed/aborted платежей за час; всплеск даже при зелёном аптайме
Ошибки ЭДОЗаказы, у которых документ не проведён; блокирует отгрузку и оплату по счёту
Застрявшие отправленияПосылки со статусом, который не менялся дольше X дней (X зависит от перевозчика)
Очередь задачДлина очереди и возраст самой старой задачи
Свежесть фидовВозраст последней успешной выгрузки товарного фида (см. маркетинг)

У каждого сигнала — порог и канал уведомления; часть метрик доступна напрямую в системах, часть собирается контрольными запросами («раз в час — запрос к API учётной системы, сравнить число заказов за вчера»). Главное — у каждого сигнала есть лимит и канал уведомления, а не «раз в неделю посмотрим на отчёты».

Нормальный путь. Клиент выбрал товар → заказ создан → остаток зарезервирован → оплата подтверждена шлюзом → магазин выписывает чек → заказ уходит в логистику → посылка вручена → события синхронизируются в учёт. Каждое звено проверяется двусторонне: заказ виден в магазине, статус подтверждён шлюзом, чек соответствует позиции, отгрузка изменяет остаток.

Аварийный путь: платёж прошёл, заказ не создался. Клиент оплатил, но сервер упал между ответом шлюза и сохранением заказа. Что должна делать система:

  1. Заказ не создан (транзакция не зафиксирована) — но шлюз деньги списал.
  2. Сверка (reconciliation) по открытым платежам: магазин пробегает по неоплаченным/незавершённым заказам, находит платежи со статусом «успешно», для которых нет заказа. По ним создаётся заказ из данных шлюза в упрощённом виде или запускается возврат.
  3. Человек (менеджер) проверяет результат: заказ создан или деньги вернули; клиент получает уведомление с извинением и точным статусом.

Обратный сценарий планируется тоже: заказ создан, уведомление об оплате не дошло (недоступность шлюза или webhook). Клиенту — повторная попытка оплаты по той же корзине, а не повторное оформление всего с нуля. Каждый из этих путей фиксируется в runbook, а не «придумывается на месте».

Третий сценарий — частичная согласованность: заказ создан, деньги списаны, но webhook потерялся. Здесь срабатывает идемпотентность и сверка: обработчик webhook воспринимает повторную отправку шлюза как обновление статуса, а не новый заказ; иначе появляются дубли чеков и двойные отправки. Сверка по открытым платежам закрывает кейс, когда повтор не пришёл вовсе.

  • Кэш с параметрами URL: страницы с utm-метками и фильтрами нельзя кэшировать одной копией «на весь трафик» — правило кэширования фиксирует, какие параметры игнорируются, а какие порождают отдельный кэш.
  • Персональные цены у одного клиента внутри общего каталога: даже одна группа B2B с индивидуальным прайсом выводит страницы каталога из-под её публичного кэша — либо короткий TTL, либо подгрузка цены отдельно.
  • Webhook replay с легитимной подписью: повторные отправки шлюза подписаны правильно; без идемпотентности ключ «подписано» не спасает от дублей.
  • Задержка очереди как «здоровое состояние»: в пиках очередь растёт — это нормально; проблема фиксируется только по порогу возраста самой старой задачи, а не по длине очереди.
  • Ручное восстановление при частичном отказе: восстановление из бэкапа ради одной перепутанной цены ломает актуальные заказы; точечные правки предпочтительнее полного restore, если целостность не задета.
  • Что кэшировать решается жёстким списком из таблицы выше, а не «по ощущению» — ошибка кэша пользователь не замечает, а магазин теряет доверие.
  • Секреты и роли дороже производительности: доступ «на всех» экономит минуты и создаёт путь к изменению цен без следа.
  • Бизнес-мониторинг дешевле, чем разбирать последствия: сигнал об отставании остатков за минуту до перепродажи дешевле, чем звонок недому клиента.
  • Сверки по платежам ставятся по расписанию (раз в сутки — минимум при активных продажах), чтобы аварийный сценарий ловился в окне, а не через неделю.