Автоматическое экранирование HTML Django
При генерации HTML-разметки по шаблону всегда есть опасность, что значение переменной будет содержать нежелательные символы. Возьмем, к примеру, такой фрагмент:
Привет, {{ name }}.
На первый взгляд, совершенно безобидный способ вывести имя пользователя, но представьте, что произойдет, если пользователь введет такое имя:
<script>alert( ‘hello’)</script>
В этом случае при отображении шаблона будет создана такая HTML- разметка:
Привет, <script>alert(‘hello’)</script>
И следовательно, броузер откроет всплывающее окно с сообщением! А что если имя пользователя содержит символ ‘<‘, например:
<b>username
Тогда шаблон породит такую разметку:
Привет, <b>username
В результате оставшаяся часть страницы будет выведена жирным шрифтом!
Очевидно, что полученным от пользователя данным нельзя слепо доверять и просто копировать их в веб-страницу, поскольку злоумышленник может воспользоваться такой брешью и нанести ущерб. При наличии подобных уязвимостей становятся возможными атаки типа «межсайтовый скриптинг» (XSS)1.
Совет ——————————————————————————————-
Дополнительные сведения о безопасности см. в главе 20.
Есть два способа избежать такой опасности:
• Пропускать каждую сомнительную переменную через фильтр escape, который преобразует потенциально опасные символы в безопасные. Поначалу именно это решение и применялось в Django по умолчанию, но оно возлагает ответственность за экранирование на разработчика шаблона. Если вы забудете профильтровать какую-то переменную, пеняйте на себя.
Подробнее с этим видом атак можно познакомиться в Википедии по адресу http://ru.wikipedia.org/wiki/MeMcaumoeuu_CKpunmuHe. - Прим. науч. ред.
• Воспользоваться автоматическим экранированием. Ниже в этом разделе мы опишем, как действует этот механизм.
По умолчанию каждый шаблон в Django автоматически экранирует значения всех шаблонных переменных. Точнее, экранируются следующие пять символов:
< преобразуется в <
> преобразуется в >
‘ (одиночная кавычка) преобразуется в '
" (двойная кавычка) преобразуется в "
& преобразуется в &атр;
Еще раз подчеркнем, что по умолчанию этот механизм включен. Если вы пользуетесь системой шаблонов Django, то можете считать себя в безопасности.
Как отключить автоматическое экранирование
Есть несколько способов отключить автоматическое экранирование для конкретного сайта, шаблона или переменной.
Но зачем вообще его отключать? Иногда шаблонные переменные могут содержать данные, которые должны интерпретироваться как HTML- код, а потому экранирование было бы излишним. Например, в вашей базе данных может храниться безопасный фрагмент HTML-кода, который вставляется в шаблон напрямую. Или вы используете систему шаблонов Django для генерации текста в формате, отличном от HTML, скажем, для вывода сообщения электронной почты.
Для отдельных переменных
Чтобы отключить автоматическое экранирование для одной переменной, воспользуйтесь фильтром safe:
Это экранируется: {{ data }} А это не экранируется: {{ data|safe }}
Можете воспринимать слово safe как safe from further escaping (защищено от последующего экранирования) или can be safely interpreted as HTML (можно безопасно интерпретировать как HTML). В примере выше, если переменная data содержит строку ‘<Ь>’, то будет выведено следующее:
Это экранируется: <b> А это не экранируется: <Ь>
Для блоков шаблона
Тег autoescape позволяет управлять автоматическим экранированием на уровне шаблона. Для этого достаточно заключить весь шаблон или его часть в операторные скобки, например:
{% autoescape off %} Привет {{ name }} {% endautoescape %}
Тег autoescape принимает в качестве аргумента on или off. Иногда требуется включить автоматическое экранирование там, где оно иначе было бы отключено. Рассмотрим пример:
Автоэкранирование по умолчанию включено. Привет {{ name }}
{% autoescape off %}
Здесь автоэкранирование отключено: {{ data }}.
И здесь тоже: {{ other_data }} {% autoescape on %}
Автоэкранирование снова включено: {{ name }} {% endautoescape %} {% endautoescape %}
Действие тега autoescape, как и всех блочных тегов, распространяется на шаблоны, наследующие текущий, а также на включаемые с помощью тега include, например:
tt base.html
{% autoescape off %}
<h1>{% block title %}{% endblock %}</h1> {% block content %} {% endblock %} {% endautoescape %}
tt child.html
{% extends "base.html" %}
{% block title %}To да ce{% endblock %}
{% block content %}{{ greeting }}{% endblock %}
Поскольку в базовом шаблоне автоматическое экранирование отключено, то оно будет отключено и в дочернем шаблоне, поэтому если переменная greeting содержит строку <b>Hello!</b>, то будет выведена такая HTML-разметка:
<h1>To да ce</h1> <Ь>Привет!</Ь>
Примечания ———————————————————————-
Обычно авторы шаблонов не задумываются об автоматическом экранировании. Но разработчики частей, написанных на Python (представлений и фильтров), должны подумать о тех случаях, когда данные не нужно экранировать, и соответствующим образом пометить их, чтобы шаблон работал правильно.
Если вы пишете шаблон, который может использоваться в ситуациях, где неизвестно, будет ли включено автоматическое экранирование, добавляйте фильтр escape к любой переменной, нуждающейся в экранировании. Если автоматическое экранирование и так включено, то двойное экранирование не нанесет никакого вреда, потому что фильтр escape не затрагивает переменные, уже подвергнутые автоматическому экранированию.
Автоматическое экранирование строковых литералов в аргументах фильтра
Как отмечалось выше, аргументы фильтра могут быть строками:
{{ data|default:"Это строковый литерал." }}
Любой строковый литерал вставляется в шаблон без автоматического экранирования, как если бы был пропущен через фильтр safe. Такое решение принято потому, что за содержимое строкового литерала несет ответственность автор шаблона, значит, он может экранировать его самостоятельно.
Следовательно, правильно писать так:
{{ data|default:"3 < 2м }} а не так:
{{ data|default:"3 < 2" }} <- Плохо! Не делайте так.
Это никак не отражается на том, что происходит с данными, поступающими из самой переменной. Содержимое переменной по-прежнему автоматически экранируется при необходимости, так как автор шаблона им не управляет.
Источник: Головатый А., Каплан-Мосс Дж. Django. Подробное руководство, 2-е издание. - Пер. с англ. - СПб.: Символ- Плюс, 2010. - 560 е., ил.