使用Python清理用户input

清理基于Python的Web应用程序的用户input的最佳方式是什么? 是否有一个单一的function来删除HTML字符和任何其他必要的字符组合,以防止XSS或SQL注入攻击?

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

它是一个http://www.djangosnippets.org/snippets/205/的修改版本,正则expression式的属性值,以防止人们使用;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 = 'pi strong bua 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注入,所以这应该几乎涵盖了你。

编辑 : 漂白是一个html5lib的包装,这使得它更容易使用作为白名单sanitiser。

html5lib提供了一个基于白名单的HTML sanitiser – 很容易将其子类化以限制用户可以在您的网站上使用的标签和属性,甚至在允许使用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编辑器组件是一个问题,但实际上,为了testingXSS Cheatsheet攻击,我实际上必须禁用JavaScript,因为将它们全部粘贴到WMD中最后会给我提醒框并清空页面。

防止XSS的最好方法不是尝试和过滤所有内容,而是简单地执行HTML实体编码。 例如,自动将<转换为<。 这是一个理想的解决scheme,假设您不需要接受任何htmlinput(在用作标记的论坛/评论区域之外,需要接受HTML应该是非常罕见的)。 通过备用编码有如此多的排列,除了超限制的白名单(az,AZ,例如0-9)之外,任何东西都会让事情通过。

SQL注入,相反的意见,仍然是可能的,如果你只是build立一个查询string。 例如,如果您只是将传入参数连接到查询string,则您将拥有SQL注入。 防止这种情况的最好方法也不是过滤,而是虔诚地使用参数化查询,而不是连接用户input。

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

Jeff Atwood自己描述了StackOverflow.com如何在Stack Overflow博客上清理用户input(以非语言特定的术语): http : //blog.stackoverflow.com/2008/06/safe-html-and-xss/

然而,Justin指出,如果你使用Django模板或类似的东西,那么他们可能会净化你的HTML输出。

SQL注入也不应该成为一个问题。 所有的Python数据库库(MySQLdb,cx_Oracle等)都会清理你传递的参数。 Python的所有对象关系映射器(如Django模型)都使用这些库,因此您不必担心其中的卫生问题。

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

当没有parsing应该发生时,我通常只是逃避数据不会干扰数据库,当我存储它,并逃离我从数据库中读取的一切不干扰HTML当我显示它(cgi.escape()inpython)。

有机会,如果有人试图inputhtml字符或东西,他们实际上希望它被显示为文本。 如果他们没有,好强硬:)

总之逃避什么可以影响当前数据的目标。

当我确实需要一些parsing(标记或其他)时,我通常试图将这个语言保留在与html不相交的集合中,所以我仍然可以将它适当地转义(在validation语法错误之后)并将其parsing为html。不必担心用户放在那里干扰你的html的数据。

另请参阅转义HTML

要清理要存储到数据库的stringinput(例如客户名称),您需要将其转义或明确删除引号(',“),这样可以有效地防止传统的SQL注入,如果您正在汇编来自用户传递的string的SQL查询。

例如(如果完全可以删除引号):

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

如果您使用的是像django这样的框架,框架可以使用标准filter轻松实现。 事实上,我很确定django会自动执行它,除非你不告诉它。

否则,我build议在接受来自表单的input之前使用某种正则expression式validation。 我不认为你的问题有一个银弹,但使用重新模块,你应该能够构build你所需要的。