Каков наилучший способ дезинформировать пользовательский ввод для веб-приложения на базе Python? Есть ли одна функция для удаления символов HTML и любых других необходимых комбинаций символов для предотвращения XSS или SQL-инъекции?
Управление пользователями с помощью Python
Ответ 1
Вот фрагмент, который удалит все теги не в белом списке, а все атрибуты тегов не будут отображаться в списке белых списков (поэтому вы не можете использовать onclick
).
Это измененная версия http://www.djangosnippets.org/snippets/205/, с регулярным выражением по значениям атрибутов, чтобы люди не могли использовать href="javascript:..."
, и другие случаи, описанные в http://ha.ckers.org/xss.html.
(например, <a href="ja	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 вы должны быть способны построить то, что вам нужно.