Каков наилучший способ обезопасить пользовательский ввод для веб-приложения на основе Python? Существует ли одна функция для удаления символов HTML и любых других необходимых комбинаций символов, чтобы предотвратить атаку XSS или SQL-инъекцией?
Если вы используете фреймворк, такой как django , фреймворк может легко сделать это за вас, используя стандартные фильтры. На самом деле, я уверен, что django автоматически сделает это, если вы не скажете, что нет.
В противном случае, я бы порекомендовал использовать какое-либо подтверждение регулярных выражений, прежде чем принимать входные данные из форм. Я не думаю, что есть серебряная пуля для вашей проблемы, но используя модуль re, вы сможете создать то, что вам нужно.
Джефф Этвуд сам описал, как StackOverflow.com очищает вводимые пользователем данные (в терминах, не зависящих от языка) в блоге Stack Overflow: http://blog.stackoverflow.com/2008/06/safe-html-and-xss/
Однако, как указывает Джастин, если вы используете шаблоны Django или что-то подобное, они, вероятно, все равно будут дезинфицировать ваш вывод HTML.
Внедрение SQL также не должно быть проблемой. Все библиотеки баз данных Python (MySQLdb, cx_Oracle и т. Д.) Всегда очищают передаваемые параметры. Эти библиотеки используются всеми объектно-реляционными картографами Python (такими как модели Django), поэтому вам не нужно беспокоиться о санитарных условиях.
Вот фрагмент, который удалит все теги, которых нет в белом списке, и все атрибуты тегов, которых нет в белом списке атрибутов (поэтому вы не можете его использовать 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')
Как говорили другие авторы, почти все библиотеки DB Python заботятся о внедрении SQL, так что это должно в значительной степени охватить вас.
Я больше не занимаюсь веб-разработкой, но когда я это сделал, я сделал что-то вроде этого:
Когда никакой разбор не должен происходить, я обычно просто избегаю данных, чтобы не мешать базе данных, когда сохраняю их, и избегаю всего, что я прочитал из базы данных, чтобы не мешать html при его отображении (cgi.escape () в питон).
Скорее всего, если кто-то попытался ввести html-символы или что-то еще, он действительно хотел, чтобы это все равно отображалось как текст. Если они не сделали, хорошо жестко :)
Короче говоря, всегда избегайте того, что может повлиять на текущую цель для данных.
Когда мне нужен был какой-то синтаксический анализ (разметка или что-то еще), я обычно пытался сохранить этот язык в непересекающемся наборе с html, чтобы я мог просто сохранить его соответствующим образом экранированным (после проверки на наличие синтаксических ошибок) и проанализировать его в html при отображении без необходимость беспокоиться о данных, которые пользователь вставил туда, мешая вашему HTML.
Смотри также Escapeing HTML
Лучший способ предотвратить XSS - это не пытаться фильтровать все, а просто делать кодировку HTML-сущностей. Например, автоматически превратить <в & lt ;. Это идеальное решение, предполагающее, что вам не нужно принимать ввод html (за пределами областей форума / комментариев, где он используется в качестве разметки, довольно редко нужно принимать HTML); существует так много перестановок через альтернативные кодировки, что что-либо, кроме ультра-ограничительного белого списка (например, az, AZ, 0-9), пропустит что-то.
Внедрение SQL, вопреки другому мнению, все еще возможно, если вы просто строите строку запроса. Например, если вы просто объединяете входящий параметр в строку запроса, у вас будет SQL-инъекция. Лучший способ защиты от этого - также не фильтрация, а религиозное использование параметризованных запросов и НИКОГДА не конкатенация ввода пользователя.
Это не означает, что фильтрация не является лучшей практикой, но с точки зрения SQL-инъекций и XSS вы будете гораздо более защищены, если будете неукоснительно использовать параметризованные запросы и HTML-кодировку сущностей.
Изменить : 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 в конечном итоге давала мне окна предупреждений и вычищала страницу.
Чтобы очистить строковый ввод, который вы хотите сохранить в базе данных (например, имя клиента), вам нужно либо экранировать его, либо просто удалить из него любые кавычки (', "). Это эффективно предотвращает классическое внедрение SQL, которое может произойти, если вы собирают SQL-запрос из строк, переданных пользователем.
Например (если допустимо полное удаление кавычек):
datasetName = datasetName.replace("'","").replace('"',"")
pg_catalog.pg_user
не содержит кавычек, но вы, вероятно, не хотите этого в ваших сгенерированных запросах. Вместо этого сделайте что-то вродеdatasetName = datasetName if datasetName in DATASETNAME_WHITELIST else sulk()
... if database API is used properly there is no chance of SQL injection
, Правильно ли вы подразумеваете использование параметризованных запросов? Это покрывает вас на 100%?