Генерация идентификаторов на фронтенде: архитектурные риски и альтернативные подходы
Описанные в статье диалоги и ситуации приведены исключительно для иллюстрации архитектурных проблем. Любое сходство с реальными разработчиками, командами или рабочими процесссами являются случайностью.
Представьте ситуацию. Вы — фронтенд-разработчик. Обсуждаете с бэкенд-коллегой, как генерировать ID для новых объектов. Предлагаете сделать на бэкенде простой метод, который будет выдавать ID порциями. Это стандартная практика, так делают все, кто заботится о безопасности и масштабируемости.
А в ответ слышите:
«Зачем? Фронт может генерировать сам. UUID v4 — это же просто. Коллизий практически не будет. А валидацию мы на бэкенде сделаем, не переживай».
Знакомая ситуация?
Если да — эта статья для вас.
А если нет — возможно, она убережет вас от будущих проблем и даст готовые аргументы для следующего спора.
Спойлер: генерация ID на фронтенде — это антипаттерн. И сейчас я объясню почему.
Часть 1. Почему вообще возникает этот спор?
На первый взгляд логика бэкенда кажется разумной:
«Зачем делать лишний запрос к серверу, если ID можно сгенерировать прямо в браузере? UUID v4 генерируется за микросекунды. Вероятность коллизии — 1 на 10^38, это меньше, чем вероятность сбоя жесткого диска. Идеальное решение!»
Звучит убедительно. Но только на первый взгляд.
Проблема в фундаментальном допущении: код на фронтенде выполняется в среде, которую полностью контролирует пользователь. Браузер — это не доверенная среда.
Никогда. Любой код, выполняющийся на клиенте, может быть изменен, подменен или скомпрометирован.
И пока вы не примете это как аксиому, любые рассуждения о «безопасной генерации на фронте» будут бессмысленны.
Часть 2. 6 главных причин, почему это плохо
Причина №1. Клиентский код можно изменить за 5 секунд
Это самый главный, фундаментальный аргумент. Пользователь — полный хозяин своего браузера. Он может открыть консоль разработчика и сделать буквально что угодно.
Пользователь может:
— Подменить любую JavaScript-функцию в рантайме;
— Перехватить и изменить любой сетевой запрос (через прокси или devtools);
— Использовать расширения браузера для модификации поведения страницы;
— Написать свой скрипт и отправить на сервер что угодно.
Вывод: нельзя доверять данным, которые приходят с клиента. Никогда. Даже если вы их сами сгенерировали.
Причина №2. Нет гарантии уникальности
«Вероятность коллизии UUID v4 ничтожно мала» — да, это правда
— Маловероятно ≠ невозможно. Теоретически коллизия может произойти в любой момент;
— При высокой нагрузке вероятность растет. Чем больше ID сгенерировано, тем выше шанс;
— Разные пользователи могут сгенерировать одинаковый ID. Два запроса с одним ID → один пользователь получит ошибку;
— Плохая энтропия. Не все генераторы случайных чисел одинаково хороши.
Реальная история из практики: один сервис генерировал ID через `Date.now()`.
В один момент два запроса пришли в одну миллисекунду — оба получили одинаковый ID. База данных упала на constraint violation. Проблему «починили» добавлением `Math.random()`, но коллизии продолжились при высокой нагрузке.
Перешли на бэкенд-генерацию — проблема ушла навсегда.
Причина №3. Уязвимость для IDOR-атак
IDOR - Insecure Direct Object — одна из самых распространенных и опасных уязвимостей веб-приложений. Она регулярно попадает в OWASP Top 10.
Даже если бэкенд проверяет права доступа (а он, конечно, должен это делать), сама возможность манипулировать ID — это лишняя поверхность для атаки.
Чем меньше входных данных доверяет бэкенд — тем безопаснее система.
Причина №4. Невозможно защититься от флуда
Когда ID генерируются на фронте, злоумышленник может организовать простую, но эффективную атаку:
Последствия:
— Ваша база данных забивается мусорными записями;
— Реальные пользователи получают ошибки или тормоза;
— Растут расходы на хранение и вычислительные ресурсы;
— Бэкенд не может отличить «честную» генерацию от вредоносной.
Rate limiting по IP? Злоумышленник использует ботнет. Капча? Это только усложнит жизнь обычным пользователям. Единственный надежный способ — контролировать выдачу ID на бэкенде.
Причина №5. Нет аудита и централизованного контроля
Когда ID рождается на клиенте, бэкенд теряет критически важную информацию:
Без этой информации вы не сможете:
— Расследовать инциденты безопасности;
— Отследить необычную активность;
— Подготовить отчет для регулятора;
— Понять, кто на самом деле создал подозрительную запись.
В системах с требованиями к аудиту (финансы, медицина, персональные данные) генерация ID на фронте просто неприемлема.
Причина №6. Проблемы с масштабированием и B2B-сценариями
Сегодня у вас только веб-фронтенд. А завтра появится мобильное приложение, десктоп-клиент, API для партнеров.
Правильная архитектура: бэкенд — единый источник правды для ID. Только так можно гарантировать уникальность и контролируемость при любом количестве и типе клиентов.
Часть 3. А что насчет валидации на бэкенде?
«Ну и пусть фронт генерирует, мы всё проверим на своей стороне!» — часто слышу я в спорах.
Давайте разберем, что может проверить бэкенд, а что — нет.
Валидация проверяет факты, но не может проверить намерения. Злоумышленник всегда может сгенерировать ID в любом формате — и бэкенд не сможет это предотвратить.
Валидация — это защита от случайных ошибок, а не от злонамеренных атак.
Часть 4. Еще 15 причин (для самых любопытных)
Шести причин обычно достаточно, чтобы убедить. Но бывают случаи, когда нужна тяжелая артиллерия.
Проблемы с данными и целостностью
7. Потеря контекста создания ID
Бэкенд не знает, когда и при каких обстоятельствах был создан ID. timestamp с клиента нельзя доверять — его легко подделать.
8. Проблема каскадного обновления
Если объекты ссылаются друг на друга, замена ID на бэкенде ломает все ссылки.
9. Нарушение идемпотентности
При повторной отправке того же запроса (например, из-за медленного интернета) возникает конфликт уникальности.
Проблемы с производительностью
10. Проблема «горячих» индексов при строковых ID
UUID v4 вставляется в случайное место B-Tree индекса, вызывая постоянную перебалансировку. При 10 000+ вставок/сек это становится узким местом.
11. Проблема пагинации и сортировки
Сортировка по UUID не равна сортировке по времени создания.
Проблемы с безопасностью (расширение)
12. Утечка информации о бизнес-метриках
Конкуренты могут анализировать темпы роста вашего бизнеса по «расходу» ID.
13. Атака через истощение пула ID
Если ID имеют ограниченный диапазон (например, 6-значный номер заказа), злоумышленник может исчерпать все доступные ID.
14. Проблема с GDPR и «правом на забвение»
При удалении данных пользователя сложно найти все связанные объекты.
Проблемы с отладкой и эксплуатацией
15. Сложность воспроизведения багов
«У меня ошибка с объектом abc-123» — без доступа к машине пользователя невозможно понять, что произошло.
16. Проблема миграции данных
Смена формата ID требует координации между всеми клиентами одновременно.
17. Проблема тестирования
E2E-тесты не могут предсказать, какой ID будет создан.
Юридические и комплаенс-риски
18. Аудит для регуляторов
ФНС, PCI DSS, HIPAA, GDPR требуют доказательств, кто и когда создал каждую запись.
19. Требования к последовательности ID
Некоторые регуляторы требуют строго возрастающие номера счетов/заказов.
---
Часть 5. Как правильно?
Архитектурно верное решение выглядит так:
Почему это правильно?
А как же производительность?
Один дополнительный запрос на пачку из 50-100 ID — это ничтожная нагрузка. Особенно по сравнению с рисками, которые вы получаете при генерации на фронте.
Часть 6. Готовые аргументы для дискуссии с бэкендом
Если ваш бэкенд-коллега все еще настаивает на своем, используйте эти фразы.
Если говорит: «Мы будем валидировать на своей стороне»
«Валидация проверяет формат и уникальность, но не может проверить "честность" генерации. Злоумышленник может генерировать ID в любом формате, и вы не сможете это предотвратить. Вы предлагаете доверять данным из ненадежного источника — это базовая ошибка безопасности.»
Если говорит: «Коллизии UUID маловероятны»
«Коллизии маловероятны, но не невозможны. При высокой нагрузке вероятность растет. Кроме того, проблема не только в коллизиях, но и в атаках, флуде, предсказуемости и отсутствии аудита. Почему вы хотите перенести ответственность за уникальность на клиента?»
Если говорит: «Не хочу делать лишний метод»
«Метод генерации ID — это 15 строк кода на бэкенде. Если мы не можем договориться о такой простой вещи, какие у нас будут отношения по сложным задачам? Это вопрос архитектурной принципиальности.»
Если говорит: «Это оптимизация, меньше запросов»
«Мы говорим о 1 дополнительном запросе на пачку из 50-100 ID. Это ничтожная нагрузка. Ценой микрооптимизации вы приносите в жертву безопасность и надежность. Это неправильный trade-off.»
Если говорит: «В Google/Amazon так делают»
«Нет, не делают. В Google ID генерируются на бэкенде. Snowflake, Twitter Snowflake, Instagram ID — все это бэкенд-генераторы. Покажите мне хоть один крупный сервис, который доверяет генерацию ID клиенту.»
Часть 7. Что делать, если бэкенд не сдается?
Вариант 1. Эскалация
Вынесите вопрос на архитектурное обсуждение с Tech Lead или Архитектором. Это не «мнение фронтенда», это базовая безопасность и архитектурная грамотность.
Вариант 2. Зафиксировать риск
Создайте документ с описанием рисков и получите подписи.
Вариант 3. Компромисс (костыль)
Если бэкенд категорически отказывается, предложите схему с временными ID:
Но это всё равно костыль. Правильное решение — метод на бэкенде.
---
Часть 8. Когда генерация на фронте все-таки допустима?
Справедливости ради, есть сценарии, где фронтенд-генерация ID может быть оправдана.
1. Оптимистичный UI (временные ID)
2. Оффлайн-режим
Приложение генерирует ID локально, а при синхронизации бэкенд заменяет их на свои.
3. Прототипы и pet-проекты
Когда скорость разработки важнее безопасности и масштабируемости.
4. Абсолютно изолированные системы
Без сетевого взаимодействия, без БД, без нескольких пользователей.
Но для production-систем с высокой нагрузкой и требованиями к безопасности — никогда.
Часть 9. Чеклист для принятия решения
Перед тем как принять решение о генерации ID, ответьте на эти вопросы:
[ ] В системе есть больше одного пользователя?;
[ ] В системе есть больше одного сервера/инстанса БД?;
[ ] Есть требования к безопасности?;
[ ] Нужен аудит действий пользователей?;
[ ] Есть требования регуляторов (ФНС, PCI DSS, HIPAA, GDPR)?;
[ ] Планируются B2B-интеграции?;
[ ] Есть мобильное приложение (не вебвью)?;
[ ] Возможна высокая нагрузка (>1000 RPS)?;
[ ] Нужна возможность отладки инцидентов?;
[ ] Планируется масштабирование в будущем?.
Если вы отметили хотя бы 3 пункта — генерация ID на фронтенде не для вас.
---
Заключение
Генерация ID на фронтенде — это антипаттерн. Он основан на ложном допущении о том, что клиентскому коду можно доверять. На самом деле браузер пользователя — это враждебная среда, и любые данные, приходящие с клиента, должны рассматриваться как потенциально опасные.
Ваша задача — мягко, но настойчиво объяснить эти риски и настоять на правильном архитектурном решении. Или как минимум зафиксировать, что решение было принято против ваших рекомендаций.
Помните: безопасность — это общая ответственность. И иногда приходится спорить с коллегами, чтобы защитить систему от будущих проблем.
Ссылка на оригинальную статью: