taint. Задание преобразований данных

^taint[текст]
^taint[вид преобразования][текст]


C помощью механизма автоматических преобразований Parser защищает сайты от вторжения извне и «по умолчанию» делает это хорошо. Этот механизм работает, даже если в коде нет ни одного оператора 
taint. Вмешиваясь в работоспособность этого механизма с помощью данных операторов (особенно используя вид преобразования as-is), легко создать уязвимость в разрабатываемом сайте, поэтому делать это нужно внимательно, обязательно разобравшись, как же именно он работает.

Оператор
taint помечает весь переданный ему текст как нуждающийся в преобразовании заданного вида. Если вид преобразования не указан, оператор taint помечает текст как tainted (неопределенно «грязный», без указания вида преобразования). Для помеченного таким образом текста будут применяться такие же правила преобразований как для текста, пришедшего извне (из полей формы, базы данных, файла, cookies и т. п.).

Данный оператор лишь делает пометки в тексте о виде преобразования, который Parser должен будет произвести
позже, но не производят его сиюминутно. Сами преобразования Parser выполняет или при выполнении оператора apply-taint или при выдаче текста в браузер, перед выдачей SQL-серверу, при сохранении в файл, при отправке письма и т. п.

Для простоты можно представить себе, что вокруг всех букв, пришедших извне, написано
^taint[пришедшее извне], а вокруг всех букв, набранных в теле страницы, - ^taint[optimized-as-is][написанное разработчиком].

Автоматические преобразования защищают от небезопасных внешних данных. Например, если при составлении SQL-запроса написать (опять же без использования
taint):
^string:sql{SELECT name FROM table WHERE uid = '$form:uid'},
то злоумышленник не сможет выполнить SQL injection, передав в качестве параметра, например, «?uid=' OR 1=1 OR '», т. к. Parser перед выдачей SQL-серверу текста запроса экранирует в пришедшем от пользователя $form:uid одинарные кавычки.

Текст, написанный разработчиком в теле страниц, также подвергается автоматическому преобразованию. В нем Parser выполняет оптимизацию пробельных символов (включая пробел, табуляцию, символ перевода строки). Идущие подряд перечисленные символы заменяются только одним, который встречается в коде первым. То есть при вставке в текст страницы нескольких идущих подряд пробельных символов перед выдачей их в браузер посетителю от них останется только первый символ. Если в каких-то случаях нужно отключить эту оптимизацию (например, для выдачи в 
<pre/>), то необходимо сделать это явно, например, написав вокруг текста:

<pre>
^taint[as-is][
  Я
   достаю
         из широких штанин
  дубликатом
            бесценного груза.      
  Читайте,
          завидуйте,
                    я -               
                       гражданин
  Советского Союза.
]

</pre>

В данном случае нужно писать именно 
taint, а не untaint, т. к. буквы, написанные в тексте страницы разработчиком, являются «чистыми», и поэтому untaint не окажет на них никакого влияния.


Пример
$clean[<br />]
предыдущая запись эквивалентна следующей: $clean[^taint[optimized-as-is][<br />]]
$tainted[^taint[
<br />]]

Строки: ^if($clean eq $tainted){совпадают}{не совпадают}<br />

«Грязные» данные - '$tainted'<br />
«Чистые» данные - '$clean'<br />

Из данного примера видно, что, несмотря на сообщение об эквивалентности строк, при выводе их в браузер результат различен: «чистая» строка выводится без преобразований, а в «грязной» строке символы < и > заменены
&lt; и &gt; соответственно.


Пример

$town[Москва]
<a href="town.html?town=^taint[uri][$town]">$town</a>

В результате данные, хранящиеся в переменной
town, будут помечены как нуждающиеся в преобразовании к типу URI и позже, при выводе в браузер, кириллические буквы будут заменены шестнадцатеричными кодами символов и представлены в виде %ХХ.


Пример
Вывод данных, полученных от пользователя на странице, сохранение их
в БД и создание на их основе XML<br />

Указано: '$form:field'
^connect[$SQL.connect-string]{

   ^void:sql{INSERT INTO news SET (body) VALUES ('$form:field')}
}

$doc[^xdoc::create{
<?xml version="1.0" encoding="WINDOWS-1251"?>
<root>
   <data>
$form:field
</data>
</root>
}]


В данном случае
taint использовать не нужно вовсе, т. к. необходимые преобразования будут сделаны автоматически, причем при выводе в браузер будет сделано преобразование optimized-html, при выдаче SQL-серверу - sql, а при формировании XML - xml.

Обратим внимание на то, что при сохранении данных в БД в административном интерфейсе также не требуется писать
taint в SQL-запросах.


Пример

Выдача даннных (могут содержать теги), пришедших от пользователя или из БД,
в форму для редактирования<br />
^if(def $form:body){
   $body[$form:body]
}{
   ^connect[$SQL.connect-string]{
      $body[^string:sql{
SELECT body FROM news WHERE news_id = $id}]
   }
}
<textarea>$body</textarea>

В данном случае сработает автоматическое преобразование
optimized-html, т. к. данные, пришедшие из БД или от пользователя, являются «грязными». Поэтому встретившиеся в данных теги не «поломают» страницу. Нужно иметь в виду, что если в данных есть идущие подряд пробельные символы, то они будут оптимизированы при выдаче в браузер.


Пример
Выдача данных с тегами из БД, помещенных туда администратором:<br />
^connect[$SQL.connect-string]{
   $body[^string:sql{
SELECT body FROM news WHERE news_id = $id}]
}

^taint[as-is][$body]

В данном случае необходимо использовать taint с видом преобразования as-is, т. к. требуется, чтобы теги в тексте новости, помещенные туда администратором, были выданы именно как теги и в них не было произведено никаких преобразований. Ни в коем случае нельзя выводить подобным образом данные из БД, полученные от посетителей сайта (например, данные гостевых книг, форумов и т. д.).


Пример
Выдача даннных (могут содержать теги), пришедших от пользователя или из БД
в форму для редактирования с сохранением пробельных символов<br />
^if(def $form:body){
   $body[$form:body]
}{
   ^connect[$SQL.connect-string]{
      $body[^string:sql{
SELECT body FROM news WHERE news_id = $id}]
   }
}
<textarea>^taint[html][$body]</textarea>

В данном случае нужно использовать
taint с видом преобразования html, чтобы встретившиеся в данных теги не «поломали» страницу и чтобы отключить оптимизацию пробельных символов.


В примерах выше можно заметить, что нам пришлось использовать оператор
taint лишь трижды: один раз для того, чтобы разрешить отображать теги в тексте из БД, помещенном туда администратором, второй раз - чтобы отключить оптимизацию пробельных символов и третий раз - чтобы выдать ссылку с query string, содержащей русские буквы таким образом, чтобы эти буквы были закодированы. Во всех остальных случаях мы вообще не использовали taint, и Parser сам все сделал правильно.

В подавляющем большинстве случаев использовать оператор
taint не нужно!


Преобразование заключается в замене одних символов другими в соответствии с внутренними таблицами преобразований. Предусмотрены следующие виды преобразований:
as-is
file-spec
HTTP-header
mail-header
uri
sql
js
json   
[3.4.1]
parser-code   [3.4.0]
regex   
[3.1.5]
xml
html

optimized-as-is

optimized-xml
optimized-html


Таблицы преобразований
as-is
Изменений в тексте не делается
file-spec
Символы * ? " < > | преобразуются в _XX,
где XX - код символа в шестнадцатеричной форме
uri
Символы за исключением цифр, строчных и прописных латинских букв, а также следующих символов: _ - . " преобразуются в %XX где XX - код символа в шестнадцатеричной форме
HTTP-header
То же, что и URI
mail-header
Если известен charset (если неизвестен, не будут работать up/low case), то фрагмент, начиная с первой буквы с восьмым битом и до конца строки, будет представлен в подобном виде:
Subject: Re: parser3: =?koi8-r?Q?=D3=C5=CD=C9=CE=C1=D2?=
sql
В зависимости от SQL-сервера
- для Oracle, ODBC и SQLite символ ' меняется на ''
- для Postgres символы
' и \ предваряются символом \
- для MySQL символы
' " и \ предваряются символом \, символы с кодами 0x00 0x0A 0x0D преобразуются, соответственно, в \0 \n \r

Для выполнения данного преобразования необходимо, чтобы код, в результате работы которого преобразование должно выполниться, находился внутри оператора 
^connect[]{}
js
Символ " преобразуется в \"
Символ '
преобразуется в \' 
Символ \ преобразуется в  \\
Символ конца строки преобразуется в \n
Символ с кодом 0xFF предваряется символом \
json
Символы " \ / предваряются символом \
Символ
конца строки преобразуется в \n
Символ табуляции преобразуется в \t
Служебные символы с кодами
0x08 0x0С 0x0D преобразуются в \b \f \r
в случае вывода не в UTF-8 все unicode-символы преобразуются в \uXXXX
parser-code
Служебные символы предваряются символом ^
regex
Символы \ ^ $ . [ ] | ( ) ? * + { } - предваряются символом \
xml
Символ & преобразуется в &amp;
Символ > преобразуется в &gt;
Символ < преобразуется в &lt;
Символ " преобразуется в &quot;
Символ ' преобразуется в &apos;
html
Символ & преобразуется в &amp;
Символ > преобразуется в &gt;
Символ < преобразуется в &lt;
Символ " преобразуется в &quot;
Символ '
преобразуется в &apos; [3.5.0]
optimized-as-is
optimized-xml
optimized-html

Дополнительно к заменам выполняется оптимизация по white spaces (символы пробела, табуляция, перевода строки).

Идущие подряд перечисленные символы заменяются только одним, который встречается в коде первым


Ряд
taint-преобразований Parser делает автоматически, так, имена и пути файлов всегда автоматически file-spec-преобразуются, и когда разработчик пишет:

^file::load[filename]

Parser выполняет…

^file::load[^taint[file-spec][filename]]


Аналогично при задании HTTP-заголовков и заголовков писем происходят преобразования
HTTP-header и mail-header соответственно. А при DOM-операциях применяется таблица преобразований file-spec (см. выше) и таблица преобразований xml.


Также Parser выполняет ряд автоматических
untaint-преобразований:
вид
что преобразуется
sql
тело SQL-запроса
xml
XML-код при создании объекта класса xdoc
optimized-html
результат страницы, отдаваемый в браузер
regex
шаблоны - регулярные выражения
parser-code
тело оператора process



Copyright © 1997–2024 Art. Lebedev Studio | http://www.artlebedev.ru Дата обновления: 28.12.2024