Руководство по XSS, часть 3 |
06.02.2020 00:00 | ||||||||||||||||||||||||||||
Авторы: Джейкоб Каллин и Ирен Лобо Валбуэна (Jakob Kallin, Irene Lobo Valbuena) Предотвращение XSSМетоды предотвращения XSS Напомним, что XSS-атака – это тип инъекции кода: вредоносный код ошибочно интерпретируется как пользовательский ввод. Чтобы предотвратить этот тип инъекций, необходимо безопасно обращаться с вводом. Для веб-разработки существует два фундаментально разных подхода к безопасной обработке вводимой информации:
Несмотря на то, что эти методы предотвращения XSS в корне различны, у них есть ряд общих характеристик, которые важно понимать при их использовании: Контекст Безопасную обработку вводимой информации нужно выполнять по-разному в зависимости от того, на каком месте страницы этот ввод применяется. Вход/выход Безопасная обработка вводимой информации может выполняться, когда ваш сайт получает ввод (на входе), или сразу перед тем, как сайт вставляет эту информацию на страницу (на выходе). Клиент/сервер Безопасная обработка вводимой информации может выполняться как на клиентской, так и на серверной стороне, и оба этих подхода должны использоваться в зависимости от ситуации. Прежде чем вдаваться в детальное описание работы шифрования и валидации, мы остановимся на каждом из этих пунктов. Контекст обработки вводимой информацииНа веб-странице существует множество контекстов пользовательского ввода данных. Для каждого из них нужно следовать специальным правилам, чтобы ввод не вырвался из своего контекста и не был интерпретирован как вредоносный код. Ниже приведены наиболее распространенные контексты.
Почему контекст – это важно Во всех вышеуказанных контекстах XSS-уязвимость возникнет, если пользовательский ввод будет вставлен без шифрования или валидации. Злоумышленник получит возможность внедрить вредоносный код, просто вставляя закрывающий разделитель для этого контекста, а затем – собственно сам код. К примеру, если на каком-то моменте сайт напрямую вставляет пользовательский ввод в атрибут HTML, злоумышленник сможет внедрить вредоносный скрипт, начав свой ввод с кавычки, как показано ниже: In all of the contexts described, an XSS vulnerability would arise if user input were inserted before first being encoded or validated. An attacker would then be able to inject malicious code by simply inserting the closing delimiter for that context and following it with the malicious code.
Это можно предотвратить, просто удаляя все кавычки в пользовательском вводе, и все будет хорошо – но только в этом конкретном случае. Если ту же самую строку ввести в другом контексте, закрывающий разделитель будет иным, и инъекция станет возможной. Поэтому безопасная обработка ввода всегда должна подгоняться под контекст, в котором пользовательский ввод вставляется на страницу. Обработка ввода на входе/выходеИнстинктивно может показаться, что XSS можно предотвратить, шифруя или валидируя весь пользовательский ввод, как только сайт получает его. В этом случае все вредоносные строки уже нейтрализованы до вывода на странице, а генерирующим HTML скриптам не надо заморачиваться безопасной обработкой входящей информации. Проблема тут в том, что, как говорилось ранее, пользовательский ввод может осуществляться в различных контекстах на странице. Нет легкого способа определить, в каком контексте будет использована прибывшая на сайт входящая информация, и та же самая пользовательская информация часто может использоваться в разных контекстах. Надежда на обработку ввода на входе с целью предотвращения XSS, следовательно, решение очень хрупкое, подверженное ошибкам. Функция обрезания "магических кавычек" в PHP – пример такого решения. Вместо этого вашей первой линией защиты от XSS должна быть обработка ввода на выходе, так как она способна учитывать контекст, в котором используется пользовательский ввод. Однако валидация на входе тоже может применяться для добавления дополнительного уровня защиты. Мы обсудим это позднее. Где нужно безопасно обрабатывать входящую информациюВ большинстве современных веб-приложений пользовательский ввод обрабатывается как серверным, так и клиентским кодом. Чтобы защититься от всех типов XSS, безопасная обработка ввода должна проводиться и на серверной, и на клиентской стороне.
Теперь, когда мы пояснили, почему так важны контекст, разница между обработкой на входе и на выходе, и безопасность обработки информации на стороне и сервера, и клиента, перейдем к объяснению, как на самом деле работают два типа безопасной обработки информации (шифрование и валидация). ШифрованиеШифрование – это способ экранирования пользовательского ввода: браузер интерпретирует его только как данные, а не как код. Наиболее распространенный тип шифрования в веб-разработке – это HTML-экранирование, трансформирующее символы вроде < и > в < и > соответственно. Псевдокод ниже – это пример того, как пользовательский ввод может быть закодирован с использованием HTML-экранирования, а затем вставлен на страницу серверным скриптом: print "<html>" Шифрование на клиентской и серверной сторонеШифруя данные на клиентской стороне, всегда пользуются JavaScript, в котором есть встроенные функции, шифрующие данные в различных контекстах. Шифруя данные на серверной стороне, вы полагаетесь на функции, имеющиеся в языке вашего сервера или фреймворка. Из-за большого количества доступных языков и фреймворков это руководство не покроет в деталях шифрование во всех них. Однако умение работать с функциями шифрования, которые используются в JavaScript на клиентской стороне, пригодится вам при создании серверного кода. Шифрование на клиентской стороне Шифруя пользовательский ввод на клиентской стороне при помощи JavaScript, можно воспользоваться рядом встроенных методов и свойств, которые автоматически шифруют всю информацию с учетом контекста: When encoding user input on the client-side using JavaScript, there are several built-in methods and properties that automatically encode all data in a context-aware manner:
Последний вышеупомянутый контекст – значения JavaScript – не включен в этот список, так как в JavaScript нет встроенного способа шифровать данные, которые должны быть включены в исходный код JavaScript. Ограничения шифрованияВ некоторых контекстах ввод вредоносных строк возможен даже при наличии шифрования. Яркий пример: пользовательский ввод используется для создания URL, как в примере ниже: document.querySelector('a').href = userInput Присвоение значения свойству опорного элемента href автоматически шифрует его, и оно становится просто значением атрибута, но само по себе это не мешает злоумышленнику вставить URL, начинающийся с "javascript:". При нажатии на такую ссылку будет выполнен JavaScript, встроенный в URL. Шифрование также не подходит как решение, если вы хотите, чтобы пользователь на самом деле управлял частью кода страницы. Например, это страница пользовательского профиля, где пользователь самостоятельно настраивает HTML. Если этот кастомный HTML зашифровать, то страница будет содержать только чистый текст. В таких ситуациях шифрование должно дополняться валидацией, о которой мы поговорим в следующий раз. |