Как стать автором
Обновить

My escape(html)

Время на прочтение4 мин
Количество просмотров1.3K
Цель поста — покритикуйте.

Изучаю Django по-маленьку, посредством создания движка для блога. Появилась проблема вывода пользовательского контента, т.е. его экранирования. Написал свою функцию. Имея кое-какой опыт в создании контента для разных сайтов с разной идеологий экранирования пользовательских данных (скорее отрицательный, в основном сайты просят делать лишнюю работу), у меня выработалась философия.

Замечание. В моём блоге в базе всегда хранится никак не обработанный оригинал пользовательского ввода. Задача функции — сделать из этого ввода html, пригодный для отображения. В простейшем случае функция может вызываться во время отображении контента (в шаблоне или view). Для улучшения производительности можно завести отдельное поле в базе, которое будет результатом работы функции экранирования, и будет обновляться во время обновления контента.

Итак, философия функци:

  • Это первооснова — любые пользовательские данные изначально считаются невалидными. Поэтому всё что не разрешено будет экранироваться.
  • Минимум работы для пользователя. Если я хочу написать конструкцию с угловыми скобками, я буду писать угловые скобки, а не буду думать о "& lt;" и т.д. Функция сама преобразует неправильные символы.
  • Тем не менее можно использовать некоторые тэги. Какие — задаётся параметром функции, или используется набор по-умолчанию. У каждого тэга есть набор валидных атрибутов. Функция будет оставлять валидные тэги и валидные атрибуты. Невалидные атрибуты будут просто удаляться из вывода, невалидные тэги будут экранироваться.
  • Следуя первооснове (и здравому смыслу) — незакрытые тэги будут автоматически закрываться. Закрывающие тэги без открывающих будут экранироваться.
  • Блог задумывается ориентированным на программерскую тематику, т.е. в блоге будут куски кода. Эти куски должны экранироваться целиком (это будет кусок кода, любого, хоть html). Для этого есть тэги <pre><code[ class="language"]>...</code></pre>. Я ориентировался на библиотеку подсветки кода highlight.js, она использует именно такой формат обрамления кода. Всё что находится внутри этого блока будет экранировано целиком. И подсвечено.
  • Я люблю колобков :) Поэтому функция должна опционально заменять смайлы на изображения.

Вот так всё просто для пользователя — пиши что хочешь, всё будет экранировано, кроме разрешённых тэгов.

Почему не готовая разметка, bbcode, markdown:
  • Что бы пользователям не учить эту новую разметку.
  • Что бы текст поста был максимально «стандартным» (html) и переносимым. Копи-пастим оригинальный текст поста, экранируем участки с кодом, вставляем в другой блог — он корректно отображается.

Хотя сделать свои компактные тэги, которые бы раскрывались в громоздкие html тэги, это хорошая идея. Скорее всего я сделаю так, что на каждый пользовательский ввод можно будет назначить свой фильтр.

Вот некоторые примеры, взятые из тестов:
# New line test
text: 'New' + os.linesep + os.linesep + 'line'
html(text): 'New' + '<br/>' + os.linesep + '<br/>' + os.linesep + 'line')

# Simple smile test
text: ':)'
html(text): '<img src="/files/smile.gif"/>')

# Smile in code block test
text: '<pre><code>there will be no image :)</code></pre>'
html(text): '<pre><code>there will be no image :)</code></pre>')

# Plain text test
text: 'Some simple text without any tags'
html(text): 'Some simple text without any tags')

# Simple tags test
text: 'This is <b>important</b> information'
html(text): 'This is <b>important</b> information')

# Wrong tag test
text: 'This is <b>important</b> information and this is <h5>title</h5>'
html(text): 'This is <b>important</b> information and this is &lt;h5&gt;title&lt;/h5&gt;')

# Wrong attributes test
text: 'This is <b onclick="javascript:alert();">probable XSS</b>'
html(text): 'This is <b>probable XSS</b>')

# Simple tags test
text: 'This is <img src="image.jpg" onclick="javascript:alert();"/>image'
html(text): 'This is <img src="image.jpg"/>image')

# Text without tags
text: 'Sample code: <?php print "Hello World"; ?>'
html(text): 'Sample code: &lt;?php print &quot;Hello World&quot;; ?&gt;')

# Code test
text: 'Sample code: <pre><code><a href="home.html">link</a></code></pre>'
html(text): 'Sample code: <pre><code>&lt;a href=&quot;home.html&quot;&gt;link&lt;/a&gt;</code></pre>')

# Closing tag without opening tag
text: '</b>bold text ended'
html(text): '&lt;/b&gt;bold text ended')

# Autoclosing tags test
text: '<b>bold and <i>italic</i> text'
html(text): '<b>bold and <i>italic</i> text</b>')

# Overlapping areas test
text: 'if 1 < 2 <b>only</b> then it is ok, but if 1 < 2 or 2 < 3 then <i>bad</i>'
html(text): 'if 1 &lt; 2 <b>only</b> then it is ok, but if 1 &lt; 2 or 2 &lt; 3 then <i>bad</i>')


К сожалению, у меня нет сервера где можно было бы показать работу функции. Она находится вот здесь: http://pastebin.com/f591d71e5.

Надеюсь на критику, спасибо.
Теги:
Хабы:
Всего голосов 8: ↑5 и ↓3+2
Комментарии7

Публикации