Управление пользователями с помощью Python

Каков наилучший способ дезинформировать пользовательский ввод для веб-приложения на базе Python? Есть ли одна функция для удаления символов HTML и любых других необходимых комбинаций символов для предотвращения XSS или SQL-инъекции?

Ответ 1

Вот фрагмент, который удалит все теги не в белом списке, а все атрибуты тегов не будут отображаться в списке белых списков (поэтому вы не можете использовать onclick).

Это измененная версия http://www.djangosnippets.org/snippets/205/, с регулярным выражением по значениям атрибутов, чтобы люди не могли использовать href="javascript:...", и другие случаи, описанные в http://ha.ckers.org/xss.html.
(например, <a href="ja&#x09;vascript:alert('hi')"> или <a href="ja vascript:alert('hi')"> и т.д.)

Как вы можете видеть, он использует (удивительную) библиотеку BeautifulSoup.

import re
from urlparse import urljoin
from BeautifulSoup import BeautifulSoup, Comment

def sanitizeHtml(value, base_url=None):
    rjs = r'[\s]*(&#x.{1,7})?'.join(list('javascript:'))
    rvb = r'[\s]*(&#x.{1,7})?'.join(list('vbscript:'))
    re_scripts = re.compile('(%s)|(%s)' % (rjs, rvb), re.IGNORECASE)
    validTags = 'p i strong b u a h1 h2 h3 pre br img'.split()
    validAttrs = 'href src width height'.split()
    urlAttrs = 'href src'.split() # Attributes which should have a URL
    soup = BeautifulSoup(value)
    for comment in soup.findAll(text=lambda text: isinstance(text, Comment)):
        # Get rid of comments
        comment.extract()
    for tag in soup.findAll(True):
        if tag.name not in validTags:
            tag.hidden = True
        attrs = tag.attrs
        tag.attrs = []
        for attr, val in attrs:
            if attr in validAttrs:
                val = re_scripts.sub('', val) # Remove scripts (vbs & js)
                if attr in urlAttrs:
                    val = urljoin(base_url, val) # Calculate the absolute url
                tag.attrs.append((attr, val))

    return soup.renderContents().decode('utf8')

Как и другие плакаты, почти все библиотеки библиотек Python позаботятся о SQL-инъекции, поэтому это должно в значительной степени покрыть вас.

Ответ 2

Изменить: bleach - это оболочка вокруг html5lib, которая делает ее еще проще использовать как белый список, основанный sanitiser.

html5lib поставляется с белым списком HTML-sanitiser - легко подклассифицировать его, чтобы ограничить теги и атрибуты, которые пользователи могут использовать на вашем сайте, и он даже пытается санировать CSS, если вы разрешаете использовать атрибут style.

Теперь я использую его в моей утилите clone sanitize_html для стека переполнения:

http://code.google.com/p/soclone/source/browse/trunk/soclone/utils/html.py

Я бросил все атаки, перечисленные в ha.ckers.org XSS Cheatsheet (которые удобно доступный в формате XML, после выполнения преобразования Markdown to HTML с использованием python-markdown2, и, похоже, выдержали хорошо.

Компонент редактора WMD, который использует Stackoverflow, в настоящее время является проблемой, однако - на самом деле мне пришлось отключить JavaScript, чтобы протестировать атаки Cheats Cheet XSS, поскольку вставка их всех в WMD закончилась тем, что я дал предупреждающие окна и гаснул страницу.

Ответ 3

Лучший способ предотвратить XSS - не пытаться фильтровать все, а просто делать кодировку HTML Entity. Например, автоматически поворачивают < в <. Это идеальное решение, предполагающее, что вам не нужно принимать какие-либо входные данные html (за пределами областей форума/комментариев, где он используется как разметка, довольно редко нужно принимать HTML); есть чересчур много перестановок с помощью чередующихся кодировок, что любой, кроме ультра-ограничительного белого списка (a-z, A-Z, 0-9, например), должен что-то пропускать.

SQL Injection, вопреки другому мнению, по-прежнему возможна, если вы просто строите строку запроса. Например, если вы просто конкатенируете входящий параметр в строку запроса, у вас будет SQL Injection. Лучший способ защиты от этого также не фильтровать, а скорее использовать религиозные методы с параметризованными запросами и НИКОГДА не конкатенировать пользовательский ввод.

Это не означает, что фильтрация не является лучшей практикой, но с точки зрения SQL Injection и XSS вы будете гораздо более защищены, если будете религиозно использовать Parameterize Queries и HTML Entity Encoding.

Ответ 4

Джефф Этвуд сам описал, как StackOverflow.com санирует пользовательский ввод (в неязыковых терминах) в блоге Stack Overflow: http://blog.stackoverflow.com/2008/06/safe-html-and-xss/

Однако, как указывает Джастин, если вы используете шаблоны Django или что-то подобное, они, вероятно, все равно дезактивируют ваш вывод HTML.

SQL-инъекция также не должна вызывать беспокойства. Все библиотеки баз данных Python (MySQLdb, cx_Oracle и т.д.) Всегда дезинфицируют параметры, которые вы передаете. Эти библиотеки используются всеми объектно-реляционными сопоставителями Python (такими как модели Django), поэтому вам также не нужно беспокоиться о санитарии.

Ответ 5

Я больше не занимаюсь веб-разработкой, но когда я это сделал, я сделал что-то вроде этого:

Если разбор не предполагается, я обычно просто избегаю данных, чтобы не мешать работе с базой данных, когда я его храню, и избегаю всего, что я читал из базы данных, чтобы не мешать html при его отображении (cgi.escape() в python).

Скорее всего, если кто-то попытался ввести html-символы или вещи, они действительно хотели, чтобы это отображалось как текст в любом случае. Если бы они этого не сделали, то жёсткие:)

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

Когда мне понадобился какой-то синтаксический разбор (разметка или что-то еще), я обычно пытался сохранить этот язык в непересекающемся наборе с html, поэтому я мог бы просто сохранить его соответствующим образом экранированным (после проверки на синтаксические ошибки) и разобрать его на html при отображении без необходимости беспокоиться о данных, которые пользователь помещает там, мешая вашему html.

См. также Экранирование HTML

Ответ 6

Чтобы отладить строковый ввод, который вы хотите сохранить в базе данных (например, имя клиента), вам нужно либо сбежать, либо просто удалить из него кавычки (', "). Это эффективно предотвращает классическую инъекцию SQL, которая может произойдет, если вы собираете SQL-запрос из строк, переданных пользователем.

Например (если допустимо полностью удалить кавычки):

datasetName = datasetName.replace("'","").replace('"',"")

Ответ 7

Если вы используете фреймворк, например django, инфраструктура может легко сделать это для вас, используя стандартные фильтры. На самом деле, я уверен, что django автоматически сделает это, если вы не скажете об этом не.

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