CSRF и XSS в AI‑созданных веб‑приложениях: паттерны и быстрые исправления
CSRF и XSS часто встречаются в AI‑созданных веб‑прототипах: узнайте уязвимые паттерны и чеклист, чтобы закрыть дыры без переписывания экранов.

Почему CSRF и XSS появляются в AI‑созданных приложениях
CSRF и XSS часто появляются в AI‑созданных веб‑приложениях по простой причине: многие прототипы создают так, чтобы выглядеть правильно и хорошо демонстрироваться, а не выдерживать реальный трафик. Страница входа, которая «работает локально», может оказаться небезопасной после развёртывания, когда её будут использовать не только вы.
То, что скрывает «работает локально», — это разрыв между приватной средой разработчика и живым приложением. Локально вы редко сталкиваетесь с реальными куки между вкладками, сторонним контентом, большим объёмом пользовательского текста или расширениями браузера, которые меняют поведение страниц. В продакшне эти вещи возникают быстро, и одна небезопасная точка может превратиться в проход на многие страницы.
AI‑сгенерированные прототипы также склонны пропускать базовые меры безопасности, потому что промпты фокусируются на функциях. Модель часто выбирает кратчайший путь: прямо рендерит пользовательский контент, хранит токены в небезопасных местах или отправляет запросы, изменяющие состояние, без надёжной защиты. В демо это выглядит нормально, но остаются дыры, например отсутствие CSRF‑токенов или внедрение HTML на страницу.
Небольшие паттерны могут иметь большой радиус разрушения. Один компонент, который использует dangerouslySetInnerHTML для рендеринга «форматированных заметок», может превратить ввод одного пользователя в скрипт, который выполнится для каждого просматривающего. Одна кнопка «Удалить», вызывающая API без CSRF‑проверок, может позволить злоумышленнику триггерить действия, используя сессию жертвы.
«Без переписывания UI» — реалистичный подход, с оговорками. Обычно не нужно перестраивать экраны или компоненты с нуля. Защитные меры добавляются под поверхностью: более безопасные значения по умолчанию для рендера, единые обёртки для запросов и проверки на стороне сервера, которые отвергают небезопасные запросы. UI может выглядеть так же, но приложению станет значительно сложнее злоупотреблять.
Если вы унаследовали кодовую базу, сгенерированную AI, и видите такие паттерны, практичный первый шаг — быстрый аудит, чтобы найти несколько уязвимых мест с наибольшим эффектом, затем закрыть их, не меняя внешнего вида приложения. FixMyMess обычно начинает именно с этого: сначала диагностика кодовой базы, затем целевые исправления.
CSRF и XSS простыми словами
CSRF и XSS путают, потому что оба могут привести к тому, что «кто‑то сделал в моём приложении то, чего я не ожидал». Разница в том, где находится контроль у злоумышленника.
CSRF (Cross‑Site Request Forgery) в одном предложении: он обманывает браузер залогиненного пользователя, чтобы тот отправил реальный запрос, который ваш сервер примет.
XSS (Cross‑Site Scripting) в одном предложении: позволяет злоумышленнику запустить управляемый им код внутри вашего сайта в браузере пользователя.
Короткий лайфхак: CSRF злоупотребляет входом пользователя (обычно куками). XSS злоупотребляет вашей страницей.
Как они связаны
Они опасны по отдельности, но ещё хуже вместе. Обычная цепочка выглядит так:
- Баг XSS запускается в приложении и читает что‑то чувствительное (например CSRF‑токен на странице или JWT в localStorage).
- Злоумышленник использует этот секрет, чтобы отправлять авторизованные запросы, которые выглядят легитимно.
- Эти запросы выполняют действия (меняют email, добавляют админа, переводят кредиты) без ведома пользователя.
Именно поэтому «мы добавим CSRF позже» часто проваливается, если дыра XSS уже есть.
Признаки, что у вас может быть каждая проблема
Если вы используете аутентификацию на основе куки, риск CSRF высок, когда важные действия выполняются одним POST без per‑request токена, или когда API принимает запросы без проверки заголовков Origin или Referer. Риск также растёт при долгоживущих сессиях («запомнить меня») и при допущении «это приватная панель» как единственной защиты.
Риск XSS велик, когда вы рендерите пользовательский контент с помощью dangerouslySetInnerHTML (или аналогов), вставляете сырой HTML из редактора WYSIWYG или Markdown без санитации, строите HTML строками и присваиваете через innerHTML, или отражаете пользовательский ввод обратно на страницу (комментарии, имена, поисковые запросы).
В AI‑сгенерированном прототипе эти две проблемы встречаются часто в быстрых сборках. Самый быстрый путь — подтвердить, какой риск реально присутствует в приложении, а затем исправить его, не меняя расположение элементов UI.
Уязвимые XSS‑паттерны, которые стоит искать в первую очередь
XSS обычно проскальзывает, когда AI‑сгенерированный UI выбирает кратчайший путь, «чтобы выглядело правильно», и в результате начинает трактовать текст как HTML. Начните с поиска всех мест, где приложение превращает пользовательский контент в разметку.
Самые быстрые сигналы тревоги
В сгенерированном коде часто встречаются несколько высокоэффектных упрощений:
- Использование
dangerouslySetInnerHTMLдля быстрого форматирования, подсветки или вставки фрагментов. - Пользовательский контент рендерится как HTML (комментарии, биографии, тикеты поддержки, превью Markdown).
- HTML строится конкатенацией строк (шаблонные строки, содержащие
\\u003cdiv\\u003e/\\u003ca\\u003e/\\u003cimg\\u003e). - Ненадёжные данные помещаются в атрибуты (особенно
href,src,styleилиdata-*) или в inline‑обработчики событий типаonclick="...". - Скопированные «функции санитации», которые убирают только несколько тегов, используют regex или только экранируют
\\u003cи\\u003e.
Реалистичная ошибка: в панели управления есть поле «Release notes», данные берутся из базы. Кто‑то вставляет \\u003cimg src=x onerror=alert(1)\\u003e, и внезапно каждый админ, открывший страницу, выполняет этот код. Это может также украсть сессионные токены, поменять текст UI или тихо отправить действия.
Что искать в коде
Сначала используйте простые поиски. Цель — составить инвентарь, а не сразу всё исправлять.
- dangerouslySetInnerHTML
- innerHTML =
- insertAdjacentHTML
- onClick=" onerror=" onload="
- href={user
- `\\u003cdiv` `\\u003c/` (внутри шаблонных строк)
Если вы унаследовали прототипы из инструментов вроде v0, Replit или Cursor, эти упрощения встречаются часто. Любая самодельная функция «sanitize» подозрительна, пока вы её не проверите. FixMyMess часто видит «санитайзеры», которые не учитывают SVG‑перегрузки, атрибуты событий или javascript: URL.
Уязвимые CSRF‑паттерны, которые стоит искать в первую очередь
CSRF проявляется, когда приложение слишком доверяет браузерной куке. Многие AI‑сгенерированные прототипы «просто работают» в разработке, потому что вы всегда залогинены, но тот же дизайн становится опасным в продакшне.
Начните с поиска любых запросов, которые меняют данные, но не доказывают, что пользователь действительно намеревался это сделать. Самый быстрый способ — смотреть на серверные маршруты и фронтенд‑вызываемые API рядом.
Паттерны высокого риска, которые стоит проверить сегодня
Распространённые высокорисковые CSRF‑паттерны включают:
- POST/PUT/DELETE запросы, которые полагаются на сессионную куку, но не отправляют CSRF‑токен (или не валидируют его на сервере).
- Куки аутентификации без явной политики SameSite (или SameSite=None без веской причины).
- GET‑эндпойнты, которые меняют состояние (например: /api/deleteUser?id=123 или /api/toggle?id=...).
- Уверенность «мы включили CORS, значит безопасно». CORS определяет, какие сайты могут читать ответы, а не какие сайты могут отправлять запросы.
- Несколько субдоменов с общими куками при слишком широкой Domain‑настройке.
Быстрый пример: в прототипе админ‑панели есть кнопка, вызывающая GET /api/approveInvoice?id=42. Если злоумышленник заставит админа загрузить страницу, триггерящую этот URL, браузер может автоматически отправить admin‑куку.
Подводные камни с куками и субдоменами
Если приложение использует app.example.com и api.example.com, будьте конкретны в области действия куки и в том, кто может отправлять аутентифицированные запросы. Широкая область куки вместе с отсутствием CSRF‑проверок — частая ловушка «работало локально».
Если вам нужен быстрый аудит, FixMyMess может оперативно отметить эти CSRF‑паттерны (включая вопросы области куки) до того, как вы начнёте трогать UI.
Закрыть CSRF, не меняя внешний вид UI
Большинство исправлений CSRF живут в куках, заголовках и серверных middleware. Поэтому обычно можно заблокировать CSRF, не переделывая ни одной страницы.
Выберите стратегию CSRF
Два распространённых подхода хорошо работают с AI‑генерированными фронтендами:
- Synchronizer token: сервер создаёт токен, хранит его в сессии и требует его для каждого запроса, изменяющего состояние.
- Double‑submit cookie: сервер ставит CSRF‑куку и требует тот же самый значение в заголовке запроса (или теле). Серверная сессия не обязательна.
Если приложение уже использует куки для аутентификации, double‑submit cookie с заголовком часто самый наименее разрушительный путь. UI остаётся прежним. Нужно лишь добавить один заголовок в клиентский API‑клиент.
Серверные проверки, не трогающие UI
Поместите проверку CSRF там, где запросы входят в бэкенд: middleware, базовый контроллер или единый guard. Применяйте её для небезопасных методов (POST, PUT, PATCH, DELETE) и только к трафику, аутентифицированному через браузерные куки.
Практичный паттерн:
- Установите CSRF‑куку при первой загрузке страницы или после логина.
- Требуйте
X-CSRF-Tokenдля небезопасных запросов. - Сравнивайте токен из заголовка с токеном в куке (отклонять при отсутствии или несоответствии).
- Пропускайте CSRF‑проверки для эндпойнтов, которые используют Authorization‑заголовки (API‑ключи, bearer‑токены) вместо куки.
- Логируйте отклонения с маршрутом и Origin, чтобы быстро ловить случайные слёзы.
Параллельно проверьте настройки куки. Используйте SameSite=Lax по умолчанию, Secure в продакшне (HTTPS) и HttpOnly для куки аутентификации. Для CSRF‑куки, возможно, нужен HttpOnly=false, если браузер должен прочитать её и скопировать в заголовок.
Если у вас есть API, которыми пользуются и браузерный код, и серверный (SSR, cron, вебхуки), разделите доступ: маршруты с куками получают CSRF‑проверки; маршруты с токенами — нет. Команды часто просят FixMyMess аккуратно добавить такое разделение, когда AI‑прототип начинает ломаться в проде.
Закрыть XSS, не меняя внешний вид UI
Исправления XSS не обязательно означают переделку дизайна. Чаще всего можно оставить те же компоненты и маршруты, изменив только способ рендера текста и HTML. В AI‑сгенерированных приложениях UI обычно выглядит нормально, но безопасные настройки рендера отсутствуют.
Сделайте «только текст» поведением по умолчанию
Считайте любую строку недоверенной, даже если она пришла из вашей базы. Комментарии, имена профиля, «заметки», сообщения поддержки и всё, что генерирует LLM, может содержать скрытый HTML.
Сфокусируйтесь на нескольких шаблонах, которые закрывают большинство дыр:
- Уберите или строго ограничьте использование
dangerouslySetInnerHTML(и аналогичных API в других фреймворках). - Рендерьте пользовательский контент как plain text по умолчанию (без интерпретации HTML).
- Если нужен rich text, санитизируйте его библиотекой с хорошей репутацией и небольшим allowlist’ом.
- Поместите код для кодирования вывода в одно место (хелпер/компонент), чтобы исправления применялись везде.
- Считайте Markdown тоже недоверенным (Markdown может порождать HTML в зависимости от парсера).
Если HTML действительно нужен (например, редактор «release notes»), делайте санитацию прямо перед рендером и разрешайте только небольшой набор тегов (b, i, em, strong, a). Избегайте inline‑обработчиков событий, inline‑стилей и неизвестных атрибутов.
// Example pattern (React): sanitize before using dangerouslySetInnerHTML
const safeHtml = sanitize(userProvidedHtml, { allowTags: ['b','i','em','strong','a'] });
return \u003cdiv dangerouslySetInnerHTML={{ __html: safeHtml }} /\u003e;
Добавьте CSP как страхующую сетку
Content Security Policy (CSP) не исправит плохо рендерящийся код, но может ограничить вред, если что‑то проскочит.
Начните с простого и тестируйте приложение, ослабляя политику только там, где это действительно нужно:
- Блокируйте inline‑скрипты, когда это возможно.
- Разрешайте скрипты только с вашего домена.
- Запретите
javascript:URL в ссылках. - Избегайте
unsafe‑eval, если в этом нет острой необходимости.
Если вы унаследовали AI‑сгенерированный прототип и не знаете, откуда идёт небезопасный HTML, хороший рабочий процесс — найти все рискованные пути рендера, заменить их безопасными настройками по умолчанию, а затем добавить CSP, чтобы поймать остатки.
Пошаговое укрепление менее чем за день
Большинство дыр CSRF и XSS можно закрыть, не трогая layout. Хитрость — сначала работать как тестировщик, а потом заплатить минимальную площадь поверхности.
Начните с картирования потоков данных. Быстро составьте инвентарь, где данные входят (формы, query‑параметры, куки, вебхуки, поля rich text) и где они показываются пользователю (таблицы, тосты, страницы профилей, админ‑панели). Это часто выявляет скрытые пути, например внутреннюю страницу настроек, которая никогда не проверялась.
Далее сделайте исправления видимыми. Включите серверные логи для отказов CSRF (отклонённые токены, неверные origin). Для XSS добавьте явный сигнал, когда санитация что‑то удаляет. Если пользователь жалуется «мой текст исчез», вы должны видеть, что именно было удалено и почему.
План быстрых правок
- Добавьте CSRF‑защиту для всех маршрутов, изменяющих состояние (POST, PUT, PATCH, DELETE) через общее middleware, и подтвердите, что куки имеют разумные настройки (HttpOnly, Secure, SameSite).
- Упорядочьте, как клиент отправляет токен (заголовок или скрытое поле), чтобы не фиксировать это в пяти разных местах.
- Поискать
dangerouslySetInnerHTMLи похожие паттерны. Уберите их, когда можно, или изолируйте в единственный компонент, который всегда санитизирует. - Санитизируйте недоверенный HTML на одной границе (перед рендером или при сохранении). Выберите одно место, задокументируйте и следуйте этому правилу.
- Добавьте базовый CSP и прогоните ключовые сценарии, чтобы поймать случайные inline‑скрипты.
После этого протестируйте как обычный пользователь: зарегистрируйтесь, войдите, обновите профиль, отправьте форму и используйте админ‑функции. Попробуйте те же действия в другом браузере, где вы не залогинены. Если что‑то ломается, логи подскажут, была ли проблема в CSRF‑защите или в санитации.
Если вы унаследовали запутанную AI‑сгенерированную кодовую базу, FixMyMess может быстро провести аудит и применить эти заплатки с экспертной человеческой верификацией, чтобы дать вам улучшения безопасности без полного переписывания.
Пример: прототип‑панель, которая ломается в продакшне
Частая конфигурация — «админ‑панель» плюс публичный блок комментариев. UI выглядит нормально: админы могут одобрять пользователей, выдавать возвраты и менять цены. Посетители оставляют обратную связь, которая появляется в ленте на панели.
XSS просачивается, когда комментарии рендерятся как HTML. Типичный паттерн — React‑компонент с dangerouslySetInnerHTML, чтобы переносы строк и ссылки «просто работали». Если посетитель введёт код, который превращается в скрипт, он выполнится в браузере админа при открытии панели.
CSRF просачивается, когда админ‑действия полагаются только на куки для аутентификации. Кнопки вызывают эндпойнты вроде /api/admin/refund, а сервер считает, что «наличие куки = админ подтвердил действие». Если админ залогинен и затем откроет вредоносную страницу в другой вкладке, та страница может автоматически отправить скрытую форму или запрос в ваше приложение, и браузер прикрепит admin‑куку.
Реалистичный вектор атаки: злоумышленник публикует комментарий, который выполняется в сессии админа, затем вызывает запросы к CSRF‑свободным эндпойнтам для изменения состояния. Это не магия — это браузер, делающий то, что он всегда делает.
Минимальные исправления, сохраняющие те же экраны и UX:
- Перестать рендерить сырой HTML комментариев. Рендерьте текст по умолчанию или санитизируйте, разрешая только небольшой набор безопасных тегов (жирный, курсив, ссылки).
- Добавьте CSRF‑защиту для всех запросов, изменяющих состояние, и требуйте её для POST/PUT/PATCH/DELETE.
- Установите сессионные куки в
SameSite=Lax(илиStrict, где возможно) иHttpOnly. - В качестве запасной меры требуйте проверки Origin или Referer для чувствительных админ‑действий.
Команды часто приводят такую панель в FixMyMess, когда она «работает локально», но проваливает реальный аудит. Хорошая новость — обычно это можно исправить без изменения UI.
Распространённые ошибки и ложные исправления
Многие быстрые правки кажутся «безопасными», потому что они убирают предупреждение или закрывают очевидный эксплойт. Настоящая проблема часто в том, что тот же небезопасный паттерн встречается в двух‑трёх местах, которые вы забыли проверить.
Один из типичных капканов — экранировать ввод в одном месте (например, в обработчике формы), а затем рендерить те же данные по другому пути, который пропускает экранирование. Пример: поле «notes» экранируется при сохранении, но превью использует dangerouslySetInnerHTML и возвращает выполнение скрипта.
Ещё одна ошибочная фиксация — санитация только в браузере и доверие результату на сервере. Злоумышленники не пользуются вашим UI. Они отправляют запросы напрямую, поэтому сервер должен валидировать, а приложение — кодировать вывод независимо от клиента.
Люди также ошибочно считают, что JSON «безопасен». Это не так. Если вы берёте поля JSON и внедряете их в HTML (шаблоны, подсказки, тосты, rich text компоненты), вы всё ещё можете получить XSS. Формат ответа не даёт защиты — важно, как вы его рендерите.
Сторонние виджеты часто забывают проверить. Чат‑виджеты, аналитика, markdown‑редакторы и embed‑компоненты могут вставлять HTML или скрипты. Даже если ваш код чист, неверная конфигурация виджета может всё испортить.
Для CSRF частая ошибка — защитить один эндпойнт и оставить другой, изменяющий состояние, открытым. UI может вызывать /settings/update, но также есть /settings/save или /api/admin/promote, которые всё ещё принимают куки без проверки CSRF‑токена.
Быстрые проверки реальности, которые ловят большинство «исправлено, но всё ещё уязвимо» приложений:
- Ищите все пути рендера пользовательского контента, не только форму, которая его собирает.
- Принудительно выполняйте серверную валидацию и кодирование вывода, даже если клиент санитизирует.
- Просмотрите маршруты, изменяющие состояние (POST, PUT, PATCH, DELETE) и подтвердите, что все они требуют CSRF‑защиты.
- Составьте инвентарь сторонних скриптов и компонентов и проверьте, как они вставляют контент.
Команды часто приносят в FixMyMess прототип, который «работает» в демо, но проваливает эти проверки в продакшне. Быстрые выигрыши обычно приходят от закрытия дополнительных путей рендера и забытых эндпойнтов, а не от переписывания UI.
Быстрый чеклист перед релизом
Перед тем как пушить AI‑созданный прототип реальным пользователям, сделайте один проход, сфокусированный на двух общих лазейках: изменения состояния без CSRF‑защиты и недоверенный контент, который может стать скриптом.
- Защитите каждый маршрут, изменяющий состояние (POST/PUT/PATCH/DELETE). Требуйте CSRF‑токен (или эквивалентной защиты) и отклоняйте запросы без него.
- Закройте куки: ставьте Secure и HttpOnly, где возможно, и подбирайте значение SameSite под ваши сценарии (следите за сторонними редиректами и встроенными приложениями).
- Не рендерьте недоверенный HTML без санитации с allowlist’ом. Если HTML не нужен — рендерьте plain text.
- Добавьте CSP и протестируйте ключевые страницы с включённой политикой. Политика, блокирующая inline‑скрипты, ловит многие случайные XSS‑пути.
- Повторно протестируйте вход, регистрацию, сброс пароля и выход после изменений. Исправления безопасности иногда ломают аутентификацию в мелочах (токены не отправляются, куки не ставятся, редиректы зацикливаются).
Затем прогоните небольшой набор преддеплойных тестов:
- Откройте приложение в приватном окне и подтвердите поведение куки после логина.
- Попробуйте отправить запрос, изменяющий состояние, без CSRF‑токена и убедитесь, что он отклонён.
- Вставьте безобидный XSS‑зонд (например
\\u003cimg src=x onerror=alert(1)\\u003e) в любое поле, которое потом отображается на странице; убедитесь, что он рендерится как текст и не выполняется. - Откройте ключевые страницы с включённым CSP и проверьте, что ничего критичного не ломается (кнопки, модальные окна, отправки форм).
Если вы унаследовали AI‑сгенерированную кодовую базу и эти проверки обнаруживают множество крайних случаев, FixMyMess может провести аудит и патчи быстро, не требуя полного переписывания интерфейса.
Следующие шаги, если вы унаследовали AI‑сгенерированную кодовую базу
Начните с решения: нужны быстрые заплатки или короткий спринт по очистке? Если приложение маленькое, с простым логином и несколькими формами, вы часто можете закрыть главные CSRF и XSS‑дыры, не трогая UI. Если в коде много копипастной логики аутентификации, множества ad‑hoc API вызовов и везде разбросан рендеринг HTML, обходных путей станет много, и простые патчи превратятся в whack‑a‑mole.
Быстрые патчи подходят, когда у вас небольшое число действий с записью и все они идут через один клиентский обёртчик, пользовательский текст отображается в нескольких очевидных компонентах, и сессии/куки ведут себя консистентно по приложению.
Планируйте очистку, когда видите дублированные fetch‑вызовы, неясное владение куками/токенами или «временные» админ‑эндпойнты в продакшне.
Чтобы получить быстрый и полезный ревью, передайте ревьюеру простую карту текущего состояния. Цель — найти горячие точки, где прячутся проблемы, а не критиковать UI.
Вот что подготовить (даже грубый документ подойдёт):
- Список всех эндпойнтов, меняющих данные (метод + путь + кто может вызывать)
- Как работает аутентификация (куки vs заголовки, где создаётся сессия, поведение при выходе)
- Где рендерится или инжектится HTML (рендер‑хелперы, markdown, rich text, превью email)
- Любые сторонние встраивания или поля с пользовательским контентом (комментарии, поля профиля, загрузки)
- Где хранятся секреты (env‑файлы, клиентский бандл, логи CI)
Короткий аудит обычно быстро находит рисковые паттерны: отсутствие CSRF‑проверок для cookie‑сессий, небезопасный рендер HTML и места, где недоверенные данные попадают в DOM.
Если приложение уже ломается в продакшне, подумайте о целевом спринте по исправлению: закройте топ‑уязвимости, добавьте страховочные меры (токены, санитация, безопасные настройки), затем рефакторьте только худшие участки.
Если хотите внешние глаза, FixMyMess (fixmymess.ai) фокусируется на исправлении AI‑сгенерированных кодовых баз из инструментов вроде Lovable, Bolt, v0, Cursor и Replit, включая проблемы с ломаными auth‑потоками, утёкшими секретами, CSRF/XSS и укреплением безопасности, сохраняя интерфейс нетронутым.