Ответ вслух Middle Код-ревью спрашивают часто обновлено

Ревью: рендер пользовательского контента

Вопрос

Перед тобой код на ревью. Скажи вслух, что здесь не так - по убыванию важности.

Читай вслух, как на ревью: сначала что делает код, потом что сломано.

function Comment({ comment }) {
  return (
    <div className="comment">
      <a href={comment.authorUrl}>{comment.author}</a>
      <div dangerouslySetInnerHTML={{ __html: comment.html }} />
    </div>
  );
}

Попробуйте сами

Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.

Показать ответ и разбор

Коротко

XSS в чистом виде. comment.html приходит от пользователя и вставляется как разметка. Любой <img src=x onerror=... выполнится в контексте нашего домена - с доступом к токенам и куками.

Что должно прозвучать в ответе

  • dangerouslySetInnerHTML с пользовательским HTML - прямая XSS

  • нужна санитизация DOMPurify или рендер markdown без сырого HTML

  • authorUrl из данных может быть javascript: - тоже исполнение кода

  • у внешней ссылки нет rel=noopener noreferrer

  • нет запасного значения, если полей нет

  • второй рубеж - CSP, запрещающий инлайн-скрипты

Что могут спросить следом

  • Как безопасно отрендерить markdown от пользователя?
  • Чем поможет CSP, если XSS уже есть?

Разбор

XSS в чистом виде. comment.html приходит от пользователя и вставляется как разметка. Любой <img src=x onerror=...> выполнится в контексте нашего домена - с доступом к токенам и куками. Лечение: санитизация (DOMPurify) или, лучше, хранить markdown и рендерить его в узлы, не пропуская сырой HTML.

Вторая дыра, которую замечают реже: href={comment.authorUrl}. Значение javascript:alert(document.cookie) в атрибуте ссылки - тоже исполнение кода. URL нужно проверять по списку разрешённых схем.

Внешняя ссылка без rel="noopener noreferrer" даёт открытой странице доступ к window.opener.

И организационно: CSP, запрещающий инлайн-скрипты, превращает найденную дыру из катастрофы в неудобство.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.