Пользователь
0,0
рейтинг
7 февраля 2013 в 05:53

Разработка → Библиотека Jevix для Python


Всем доброго времени суток!
Недавно я задал вопрос на habre, про аналог библиотеки jevix для python.
Мне подсказали решение, но этих решений мне было недостаточно, да и всем известно что Jevix самая популярная библиотека для работы с html.

Для тех кто впервые слышит по Jevix

Jevix — средство автоматического применения правил набора текстов, наделённое способностью унифицировать разметку HTML/XML документов, контролировать перечень допустимых тегов и аттрибутов, предотвращать возможные XSS-атаки в коде документов.

Автором этой библиотеки для php является, хабра житель ur001, ссылка на проект jevix.ru/project


Предыстория

Мне очень нравится эта библиотека, я ее использовал и не раз в своих проектах, но как говорится времена меняются и я начал учить python + django и столкнулся с такой проблемой, взялся я делать проект где нужно жестко контролировать передаваемый html код и не дать врагу никакого шанса на XSS-атаки.

Вот только беда, я не смог найти jevix библиотеки для python или достойного аналога! Вот значит посидев подумав я и решил переписать jevix+php на jevix+python.

Поехали

Скажу сразу библиотека сырая и находится в beta режиме, всем добровольцам просьба потестить, чтоб в бою не ударить в грязь лицом.

Что еще не реализовано

  1. Автозамена, для таких символов как ( r ) на ®
  2. Добавление отступов от определенных строчек
  3. нельзя отключить расстановку br в определенных тегах, таких как object… по этому пока что отключил ее полностью


Как пользоваться?

Все банально просто, я старался оставить все как есть и даже название переменных.
Инициализируем
from jevix import Jevix
p = Jevix()

Настраиваем
p.cfgAllowTags(['ls','ddcut','a', 'img', 'i', 'p', 'b', 'u', 's', 'video', 'em',  'strong', 'nobr', 'li', 'ol', 'ul', 'sup', 'abbr', 'sub', 'acronym', 'h4', 'h5', 'h6', 'br', 'hr', 'pre', 'code', 'object', 'param', 'embed', 'blockquote', 'iframe','table','th','tr','td'])

    p.cfgSetTagShort(['br','img', 'hr', 'ddcut','ls']);

    p.cfgSetTagPreformatted(['pre','code','video', 'iframe'])

    p.cfgAllowTagParams('img', {
        0:'src', 'alt' : '#text', 1:'title', 'align': ['right', 'left', 'center', 'middle'],
        'width':'#int', 'height':'#int', 'hspace':'#int', 'vspace':'#int',
        'class' : ['image-center', 'image-left', 'image-right']
    })
    p.cfgAllowTagParams('a', {
        0:'title', 1:'href', 'rel' : '#text', 'name' : '#text', 'target' : ['_blank']
    })

    p.cfgAllowTagParams('ddcut', {
        0:'name',
        })

    p.cfgAllowTagParams('acronym', {
        0:'title',
        })

    p.cfgAllowTagParams('abbr', {
        0:'title',
        })

    p.cfgAllowTagParams('param', {
        'width' : '#int', 'height' : '#int',
        'src' : {'#domain':['youtube.com','rutube.ru','vimeo.com']}
    })

    p.cfgAllowTagParams('iframe', {
        'name' : '#text',
        'value' : '#text',
        'height' : '#int',
        'width' : '#int',
        'src' : {'#domain':['youtube.com','rutube.ru','vimeo.com','video.yandex.ru']},
    })

    p.cfgAllowTagParams('ls', {
        'user' : '#text'
    })

    p.cfgAllowTagParams('td', {
        'colspan':'#int','rowspan':'#int','align':['right', 'left', 'center', 'justify'],
        'height':'#int','width':'#int'
    })

    p.cfgAllowTagParams('table', {
        'border':'#int',
        'cellpadding':'#int','cellspacing':'#int','align':['right', 'left', 'center'],
        'height':'#int','width':'#int'
    })

    p.cfgAllowTagParams('embed', {
        'src' : {'#domain':['youtube.com','rutube.ru','vimeo.com','video.yandex.ru']}, 'type' : '#text',
        'allowscriptaccess' : '#text',
        'allowfullscreen' : '#text','width' : '#int', 'height' : '#int', 'flashvars': '#text',
        'wmode': '#text'
    })

    p.cfgAllowTagParams('object', {
        'width' : '#int',
        'height' : '#int',
        'data' : {'#domain':['youtube.com','rutube.ru','vimeo.com','video.yandex.ru']},

    })



    p.cfgSetTagParamsRequired('img', ['src'])
    p.cfgSetTagParamsRequired('a', ['href'])
    p.cfgSetTagParamsRequired('iframe', ['src'])

    p.cfgSetTagCutWithContent(['script',  'style'])

    p.cfgSetTagChilds('ul', ['li'], False, True)
    p.cfgSetTagChilds('ol', ['li'], False, True)
    p.cfgSetTagChilds('object', ['param'], False, True)
    p.cfgSetTagChilds('object', ['embed'], False, False)
    p.cfgSetTagChilds('table', ['tr'], False, True)
    p.cfgSetTagChilds('tr', ['td','th'], False, True)

    p.cfgSetTagIsEmpty(['param','embed','a','iframe']);
    p.cfgSetTagNoAutoBr(['ul','ol','object','table','tr'])
    p.cfgSetTagBlockType(['h4','h5','h6','ol','ul','blockquote','pre','table','iframe', 'object'])

    p.cfgSetAutoBrMode(True)

    p.cfgSetTagNoTypography(['code','video','object', 'iframe'])

errors = []
text= u"""<iframe width="560" height="315" src="http://youtube.com/embed/lGnGQXUeaVc" frameborder="0" allowfullscreen></iframe>"""



Ну и выполняем
text, errors = p.parse(text)
print text, errors


Ссылки:
на официальный проект — jevix.ru
чтоб потестить в online python+jevix — jevix.vir-mir.ru
проект на github — github.com/vir-mir/jevix
Алексей Фирсов @lesha_firs
карма
2,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (26)

  • 0
    def eror(self, message):

    Так торопились, так торопились? :)
    • +2
      нет, именно так и называет функция в php версии, я не знаю какими побуждениями пользовался автор назвав ее так.
      • 0
        Так это еще хуже, вы даже не смотрели что переносили...?
  • 0
    «Автор замена» это юмор такой?)
    • 0
      извиняюсь опечатка, «Автозамена»
  • +4
    Из коротенького определения так и не понял, что такое Jevix. Можно как-нибудь иначе описать? Скажем, не: «Flask — это питоний фреймворк для веб-приложений», а «Вот предположим, вам нужно сделать крупный тяжёлый сайт без использования CMS, которые генерят глагну за 0.7 секунд и жрут 60 метров памяти. Хорошей идеей в этом случае будет использовать CMF под названием Flask, ибо...». Втыкаете? Не «решение», а «проблема — решение». И… простите, но портировать с одного языка на другой полностью, не используя возможности языка, на который переносите, — как-то не очень хорошо. Может быть, не стоит повторять ошибки и опечатки исходника?..
    • 0
      Jevix преобразует HTML в безопасный HTML (без XSS) и выполняет типографические подстановки (переводит минусы в тире и т.д.).
  • 0
    Jevix — это библиотека для обработки html кода вводимого пользователем, Jevix-php используется в сайте habrahabr и играет самую важную роль, с прошью его мы можем писать такие красочно оформленные посты, комментарии и все что тут есть, а НЛО спит спокойно и не боится что кто-то запустит вредоносный js или покорежит страницу, каким нибудь css стилем…

    А Вы что-то другое описали.
  • +1
    PEP-8 и PEP-20 не одобряют.
  • +3
    В Python для такого есть отличная библиотека bleach
    • 0
      Добавлю, что для django поверх этой библиотеки есть приложение django-html_sanitizer
    • 0
      Я правильно понимаю, что можно либо разрешить использование какого-то атрибута у тега, либо не разрешить? Например
      <div style="width: 300px;">
      

      Он может разрешить либо любые style, либо никаких, да?

      Мы в своё время навелосипедили свой HTML cleaner (подробнее написал комментом ниже) именно из-за того, что нужно было чистить после WYSIWYG и хотелось получить результат как можно ближе к рельности.
      • +1
        я так понимаю вы об этом?
        bleach.readthedocs.org/en/latest/clean.html#styles-whitelist

        вроде бы все гибко настраивается, если надо — просто кастомный чистильщик можно довесить
        • 0
          Конечно, всё-равно не так гибко, как хотелось бы, но, наверно, если бы нашли эту библиотеку перед написанием велосипеда, то остановились бы на ней. Спасибо.
          • +1
            ну, я думаю эта библиотека покрывает бОльшую часть необходимого. у меня по крайней мере не хватает фантазии, что бы еще я от нее мог желать :)
            • 0
              Пример высосан из пальца, но во всяких object, params есть атрибуты, которых не должно (порой они не мешают, но чем чище — тем лучше) быть у других тегов. То есть нужен не список всех тегов и список всех возможных атрибутов, а по сути иерархический набор правил (ну, по крайней мере, в своём велосипеде мы так и сделали :))

              {
                   тег, {
                       разрешённый атрибут: {
                          разрешённый стиль, (разрешённые значения данного стиля),
                          ...
                      },
                      ...
                  },
                  ...
              }
              
              • +1
                ну у них почти так и сделано на самом деле:

                теги задаются списком
                атрибуты задаются словарем тег: разрешенные атрибуты (тег может быть *)
                стили так же задаются словарем тег: разрешенные стили для этого тега (также разрешается *)

                единственное что они не сделали — еще шага вглубь с валидацией значений стиля, я понимаю что это может иногда пригодиться, но думаю не так уж часто.
      • +1
        Если я правильно понял задачу, то валидацию значений аттрибутов можно реализовать при помощи callable-filters
        PS: Опередили пока писал.
  • +1
    У меня тоже была необходимость чистить вводимый пользователями html, тогда мы с ilblackdragon написали свой велосипед и по сей день он отлично работает. Одна беда — никак не вынесем велосипед в отдельный проект и живёт он у нас в django-misc вот тут — HTML cleaner.

    Логика достаточно простая — есть white-list, описанный в needs.cfg, из которого путём python generator.py создаётся clear.py, в котором мы ходим по DOM и на основе regexp принимаем решение оставить ли тег, если да, то какие свойства у него можно оставить. Потом можно взять clear.py как отдельный файл и вкрутить в нужный проект:

    from clear import clear_html_code
    
    clear_html_code("<b>Hello world</b>")
    


    PS Меня пагает ваш Python код… правда страшно… при этом я совершенно не вижу смысла сохранять совместимость в названиях с точностью до буквы — есть очень «хорошие» примеры — Internet Explorer и Windows — они сохраняли обратную совместимость с учётом старых багов с целью того, чтобы не ломать программы, которые эти баги уже эксплуатируют…
  • 0
    Мне подсказали решение, но этих решений мне было недостаточно, да и всем известно что Jevix самая популярная библиотека для работы с html.

    Вам советовали решения на основе html5lib, можно узнать что именно было недостаточно? Я глубоко конечно не вдавался, но кажется что Вы хотите делать то же самое, но с более простой настройкой нужных аттрибутов для элементов, а смотря на wiki.whatwg.org/wiki/Sanitization_rules, code.google.com/p/html5lib/source/browse/python/html5lib/sanitizer.py, для этого мне кажется проще в html5lib.sanitizer.HTMLSanitizerMixin.sanitize_token добавить свою проверку зависящую от элемента.
  • 0
  • 0
    Зачем вы повторили Jevix с его устаревшим самостоятельным разбором HTML?

    Вы могли бы уместить библиотеку в пару сотен строк, если бы использовали какую-либо реализацию DOM. В таком случае, можно было бы иметь гораздо более гибкие правила и богатейший набор возможностей.
  • 0
    Главную вещь вы так и не решили, все white list sanitizer'ы которые я видел, достаточно хорошо удаляют не нужные теги и чистят атрибуты, но. Допустим мы хотим как на хабре вставить кусок кода, к примеру такой:

    <html>
        <p>
           habrahabr
        </p>
    </html>
    


    В вашей нынешней реализации, всё что внутри тега source тоже почистится и выведет только надпись habrahabr
    • 0
      Был не прав у вас есть тег <code> в котором не чистится внутри.
  • 0
    А почему вы взяли не Perl версию? Версия PHP давно уже заброшена и не развивается. Или на Perl не далеко ушел тоже?

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.