Баг в PHP-версии типографа Лебедева

25 October 2016, 18:43 MSK
Недавно я прикрутил к своему блогу типограф от Студии Лебедева. Типограф — это инструмент автоматической обработки текстов согласно правилам экранной типографики. Он расставляет правильные кавычки, длинные тире, удаляет мусор, добавляет неразрывные пробелы и т.д. Текст становится читать легче и приятнее, и мне не нужно делать это каждый раз вручную.
Но, когда я писал заметку про то, как создать бота для Телеграма, я столкнулся со странным багом — у меня вырезались некоторые куски текста, например, <TOKEN>. Я полез смотреть исходный код и обнаружил, что этот текст стал HTML-тэгом. Сначала у меня возникло предположение, что я накосячил с парсером разметки заметок, но, оказалось, что баг в коде типографа.
Типограф Лебедева — это веб-сервис, поэтому PHP-версия всего лишь отправляет текст на сервер и получает обработанный ответ, но также перед и после отправки выполняет некоторые преобразования.
Преобразование текста до отправки на сервер, файл remotetypograf.php, строка 87:
$text = str_replace ('&', '&amp;', $text);
$text = str_replace ('<', '&lt;', $text);
$text = str_replace ('>', '&gt;', $text);
Таким образом, текст <TOKEN> (который в исходном коде заметки выглядит как &lt;TOKEN&gt;) преобразовался в &amp;lt;TOKEN&amp;gt;. Здесь всё правильно. Но, смотрим дальше.
Преобразование ответа, полученного от сервера, файл remotetypograf.php, строка 129:
$typografResponse = str_replace ('&amp;', '&', $typografResponse);
$typografResponse = str_replace ('&lt;', '<', $typografResponse);
$typografResponse = str_replace ('&gt;', '>', $typografResponse);
Здесь нарушен порядок замен. Посмотрим, что получается. Заменяем амперсанды: &lt;TOKEN&gt;, затем заменяем угловые скобки: <TOKEN>. Теперь в исходном коде заметки будет не &lt;TOKEN&gt;, а HTML-тэг.
Чтобы исправить эту ошибку, необходимо строки 129-131 заменить на следующие:
$typografResponse = str_replace ('&lt;', '<', $typografResponse);
$typografResponse = str_replace ('&gt;', '>', $typografResponse);
$typografResponse = str_replace ('&amp;', '&', $typografResponse);
Что произойдёт тогда? Заменяем угловые скобки: &amp;lt;TOKEN&amp;gt; (ничего не поменялось в данном случае), заменяем амперсанды: &lt;TOKEN&gt; — получаем то, что нужно.
По-большому счёту, это пассивная XSS-уязвимость. Если через такой код прогнать текст, оставленный пользователями на сайте (например, комментарий), то таким образом можно подарить злоумышленникам доступ к сайту.
Тэги: PHPXSSбаг