📚 Теория: XSS в Spring MVC и шаблонах (раскрыть)
Контроллер
В MVC model.addAttribute() просто кладёт объект в модель. Servlet контейнер не добавляет экранирование сам — это задача разработчика.
⚠️ Если значение попадает в HTML, его нужно экранировать или отфильтровать.
Шаблон
Thymeleaf по умолчанию экранирует th:text, но th:utext вставляет строку как HTML. Это сделано для доверенных фрагментов.
🚫 Никогда не используйте th:utext с пользовательским вводом.
Отправляет <script>fetch('/steal?c='+document.cookie)</script>
Кладёт строку в модель без экранирования.
Через th:utext вставляет payload в DOM, скрипт выполняется.
Правильный подход: либо использовать th:text (экранированный вывод), либо очищать HTML-белым списком. Для простого текста хватит HtmlUtils.htmlEscape(body) перед помещением в модель.
Контекст
Редактор новостей отправляет черновик на endpoint /preview, чтобы отрендерить быстрый просмотр. Разработчик решил, что редакторы «свои» и можно доверять вводу. В итоге модель получает HTML без фильтрации, а шаблон выводит его через th:utext, что даёт XSS.
- Проследи цепочку:
@RequestParam→addAttribute→th:utext. - Найди строку в контроллере, которая передаёт опасные данные.
- Подскажи команде, что нужно экранировать или валидировать HTML.
Сниппет
Code Review
Референс-фигура
В контроллере нужно либо экранировать HTML, либо переключиться на безопасный вывод в шаблоне. Лучший вариант — не доверять пользовательскому вводу и чистить его.
Флаг ревью: FLAG{java-spring-xss-review}
@PostMapping("/preview")
public String previewArticle(@RequestParam("body") String body, Model model) {
String safeBody = HtmlUtils.htmlEscape(body, StandardCharsets.UTF_8.name());
model.addAttribute("preview", safeBody);
return "preview";
}
Ещё лучше — убрать th:utext из шаблона и использовать th:text, чтобы Thymeleaf автоматически экранировал вывод. Если нужен отформатированный HTML, пропустите его через белый список (например, OWASP Java HTML Sanitizer).
Проверка флага
Флаг фиксирует, что ревью завершено. Сдаём его в платформе, чтобы получить +1 лабораторию в прогрессе.