62

为基于 Python 的 Web 应用程序清理用户输入的最佳方法是什么?是否有一个函数可以删除 HTML 字符和任何其他必要的字符组合以防止XSS或 SQL 注入攻击?

4

7 回答 7

29

这是一个片段,它将删除所有不在白名单上的标签,以及不在属性白名单上的所有标签属性(所以你不能使用onclick)。

它是http://www.djangosnippets.org/snippets/205/的修改版本,在属性值上使用正则表达式以防止人们使用,以及在http://ha.ckers.org/xsshref="javascript:..."中描述的其他情况.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 注入,所以这应该几乎涵盖了你。

于 2008-08-24T16:08:37.920 回答
22

编辑bleach是 html5lib 的包装器,这使得它更容易用作基于白名单的消毒剂。

html5lib带有一个基于白名单的 HTML 清理器 - 很容易对其进行子类化以限制允许用户在您的网站上使用的标签和属性,如果您允许使用该style属性,它甚至会尝试清理 CSS。

现在我在 Stack Overflow 克隆的sanitize_html实用程序函数中使用它:

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

我已经抛出了ha.ckers.org 的 XSS Cheatsheet中列出的所有攻击(在使用python-markdown2执行 Markdown 到 HTML 转换后,这些攻击可以很容易地以 XML 格式提供,并且它似乎保持正常。

不过,Stackoverflow 目前使用的 WMD 编辑器组件是一个问题——我实际上必须禁用 JavaScript 才能测试 XSS Cheatsheet 攻击,因为将它们全部粘贴到 WMD 最终会出现警告框并空白页面。

于 2008-10-30T00:41:40.753 回答
13

防止 XSS 的最佳方法不是尝试过滤所有内容,而是简单地进行 HTML 实体编码。例如,自动将 < 变为 <。这是理想的解决方案,假设您不需要接受任何 html 输入(在用作标记的论坛/评论区域之外,需要接受 HTML 的情况应该很少见);通过替代编码有如此多的排列,除了超限制性的白名单(例如 az、AZ、0-9)之外的任何东西都会让某些东西通过。

与其他意见相反,如果您只是构建查询字符串,SQL 注入仍然是可能的。例如,如果您只是将传入参数连接到查询字符串,您将有 SQL 注入。防止这种情况的最佳方法也不是过滤,而是虔诚地使用参数化查询并且从不连接用户输入。

这并不是说过滤仍然不是最佳实践,但就 SQL 注入和 XSS 而言,如果您虔诚地使用参数化查询和 HTML 实体编码,您将受到更多保护。

于 2008-09-18T15:56:09.737 回答
6

Jeff Atwood himself described how StackOverflow.com sanitizes user input (in non-language-specific terms) on the Stack Overflow blog: https://blog.stackoverflow.com/2008/06/safe-html-and-xss/

However, as Justin points out, if you use Django templates or something similar then they probably sanitize your HTML output anyway.

SQL injection also shouldn't be a concern. All of Python's database libraries (MySQLdb, cx_Oracle, etc) always sanitize the parameters you pass. These libraries are used by all of Python's object-relational mappers (such as Django models), so you don't need to worry about sanitation there either.

于 2008-08-19T20:51:39.520 回答
4

我不再做 Web 开发了,但是当我做的时候,我做了这样的事情:

当不应该发生解析时,我通常只是在存储数据时转义数据以不干扰数据库,并在显示时转义从数据库读取的所有内容以不干扰 html (cgi.escape() 在Python)。

很有可能,如果有人试图输入 html 字符或内容,他们实际上希望将其显示为文本。如果他们没有,那就太难了:)

简而言之,总是逃避可能影响数据当前目标的内容。

当我确实需要一些解析(标记或其他)时,我通常会尝试将该语言保持在与 html 不相交的集合中,这样我仍然可以将它适当地转义(在验证语法错误之后)并在不显示时将其解析为 html不必担心用户放在那里的数据会干扰您的 html。

另请参阅转义 HTML

于 2008-08-24T16:23:13.143 回答
1

要清理要存储到数据库的字符串输入(例如客户名称),您需要对其进行转义或从其中明确删除任何引号(',“)。这有效地防止了经典的 SQL 注入,如果您正在从用户传递的字符串组装 SQL 查询。

例如(如果完全删除引号是可以接受的):

datasetName = datasetName.replace("'","").replace('"',"")
于 2009-10-01T12:21:45.900 回答
0

如果您使用的是django之类的框架,则该框架可以使用标准过滤器轻松地为您完成此操作。事实上,我很确定 django 会自动执行此操作,除非您告诉它不要这样做。

否则,我建议在接受表单输入之前使用某种正则表达式验证。我认为您的问题没有灵丹妙药,但是使用 re 模块,您应该能够构建所需的内容。

于 2008-08-19T20:24:18.140 回答