Санитарная обработка пользовательского ввода с использованием Python - PullRequest
57 голосов
/ 20 августа 2008

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

Ответы [ 7 ]

26 голосов
/ 24 августа 2008

Вот фрагмент, который удалит все теги, отсутствующие в белом списке, и все атрибуты тегов, отсутствующие в белом списке атрибутов (поэтому вы не можете использовать 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 db заботятся о внедрении SQL, так что это должно в значительной степени охватить вас.

21 голосов
/ 30 октября 2008

Редактировать : bleach - это обертка вокруг html5lib, которая делает его еще проще в качестве дезинфицирующего средства на основе белого списка.

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

Вот теперь я использую его в служебной функции sanitize_html моего клона Stack Overflow:

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

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

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

13 голосов
/ 18 сентября 2008

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

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

Это не означает, что фильтрация по-прежнему не является оптимальной практикой, но с точки зрения SQL-инъекций и XSS вы будете гораздо более защищены, если будете неукоснительно использовать параметризованные запросы и HTML-кодировку объектов.

6 голосов
/ 20 августа 2008

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

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

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

4 голосов
/ 24 августа 2008

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

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

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

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

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

См. Также Выход из HTML

1 голос
/ 01 октября 2009

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

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

datasetName = datasetName.replace("'","").replace('"',"")
0 голосов
/ 20 августа 2008

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...