【发布时间】:2010-11-06 21:31:03
【问题描述】:
cgi.escape 似乎是一种可能的选择。它运作良好吗?有什么被认为更好的吗?
【问题讨论】:
cgi.escape 似乎是一种可能的选择。它运作良好吗?有什么被认为更好的吗?
【问题讨论】:
cgi.escape 很好。它逃脱了:
< 到 <
> 到 >
& 到 &
这对于所有 HTML 来说已经足够了。
编辑:如果您有非 ascii 字符,您还想转义,以便包含在另一个使用不同编码的编码文档中,就像 Craig 说的那样,只需使用:
data.encode('ascii', 'xmlcharrefreplace')
别忘了先将data解码为unicode,使用任何编码。
但是根据我的经验,如果您从一开始就一直使用unicode,那么这种编码是没有用的。只需在末尾编码为文档标题中指定的编码(utf-8 以获得最大兼容性)。
例子:
>>> cgi.escape(u'<a>bá</a>').encode('ascii', 'xmlcharrefreplace')
'<a>bá</a>
另外值得注意(感谢 Greg)是额外的 quote 参数 cgi.escape 需要。将其设置为 True 时,cgi.escape 也会转义双引号字符 ("),因此您可以在 XML/HTML 属性中使用结果值。
编辑:请注意,cgi.escape 在 Python 3.2 中已被弃用,取而代之的是 html.escape,除了 quote 默认为 True。
【讨论】:
cgi.escape 函数运行所有不受信任的数据,是否足以防止所有(已知)XSS 攻击?
cgi.escape(yourunicodeobj).encode('ascii', 'xmlcharrefreplace') == '{{Measures 12 &#937;"H x 17 5/8"W x 8 7/8"D. Imported.}}' -- 如您所见,表达式返回 ascii 字节串,所有非 ascii unicode 字符均使用 xml 字符引用表进行编码。
cgi.escape 在转义 HTML 标签和字符实体的有限意义上应该很好地转义 HTML。
但您可能还必须考虑编码问题:如果您要引用的 HTML 在特定编码中包含非 ASCII 字符,那么您还必须注意在引用时合理地表示这些字符。也许您可以将它们转换为实体。否则,您应该确保在“源”HTML 和嵌入它的页面之间完成正确的编码转换,以避免损坏非 ASCII 字符。
【讨论】:
在 Python 3.2 中引入了一个新的 html 模块,用于从 HTML 标记中转义保留字符。
只有一个功能escape():
>>> import html
>>> html.escape('x > 2 && x < 7 single quote: \' double quote: "')
'x > 2 && x < 7 single quote: ' double quote: "'
【讨论】:
quote=True 呢?
html.escape() 默认情况下会转义引号(相比之下,cgi.quote() 不会 - 并且只会转义双引号,如果这样的话)。因此,我必须显式设置一个可选参数以使用html.escape() 将某些内容注入到属性中,即使其对属性不安全:t = '" onclick="alert()'; t = html.escape(t, quote=False); s = f'<a href="about.html" class="{t}">foo</a>'
escape() 不足以使属性安全。换句话说,这是不安全的:<a href=" {{ html.escape(untrusted_text) }} ">
href 等属性中的内联 Java 脚本的一种简单方法是设置禁止它的内容安全策略。
html.escape 确实会转义单引号和双引号。
如果您希望在 URL 中转义 HTML:
这可能不是 OP 想要的(问题没有明确指出要在哪个上下文中使用转义),但是 Python 的本机库 urllib 有一种方法可以转义需要包含的 HTML 实体安全地在 URL 中。
以下是一个例子:
#!/usr/bin/python
from urllib import quote
x = '+<>^&'
print quote(x) # prints '%2B%3C%3E%5E%26'
【讨论】:
cgi.escape扩展此版本改进了cgi.escape。它还保留了空格和换行符。返回一个unicode 字符串。
def escape_html(text):
"""escape strings for display in HTML"""
return cgi.escape(text, quote=True).\
replace(u'\n', u'<br />').\
replace(u'\t', u' ').\
replace(u' ', u' ')
>>> escape_html('<foo>\nfoo\t"bar"')
u'<foo><br />foo "bar"'
【讨论】:
对于 Python 2.7 中的遗留代码,可以通过BeautifulSoup4:
>>> bs4.dammit import EntitySubstitution
>>> esub = EntitySubstitution()
>>> esub.substitute_html("r&d")
'r&d'
【讨论】:
不是最简单的方法,但仍然很简单。与 cgi.escape 模块的主要区别 - 如果您的文本中已经包含 &amp;,它仍然可以正常工作。正如您从 cmets 看到的那样:
cgi.escape 版本
def escape(s, quote=None):
'''Replace special characters "&", "<" and ">" to HTML-safe sequences.
If the optional flag quote is true, the quotation mark character (")
is also translated.'''
s = s.replace("&", "&") # Must be done first!
s = s.replace("<", "<")
s = s.replace(">", ">")
if quote:
s = s.replace('"', """)
return s
正则表达式版本
QUOTE_PATTERN = r"""([&<>"'])(?!(amp|lt|gt|quot|#39);)"""
def escape(word):
"""
Replaces special characters <>&"' to HTML-safe sequences.
With attention to already escaped characters.
"""
replace_with = {
'<': '>',
'>': '<',
'&': '&',
'"': '"', # should be escaped in attributes
"'": ''' # should be escaped in attributes
}
quote_pattern = re.compile(QUOTE_PATTERN)
return re.sub(quote_pattern, lambda x: replace_with[x.group(0)], word)
【讨论】:
还有优秀的markupsafe package。
>>> from markupsafe import Markup, escape
>>> escape("<script>alert(document.cookie);</script>")
Markup(u'<script>alert(document.cookie);</script>')
markupsafe 包经过精心设计,可能是最通用和 Pythonic 的转义方式,恕我直言,因为:
Markup) 是从 unicode 派生的类(即isinstance(escape('str'), unicode) == True
__html__ 属性的对象)和模板重载 (__html_format__)。【讨论】:
没有库,纯python,安全地将文本转义为html文本:
text.replace('&', '&').replace('>', '>').replace('<', '<'
).replace('\'',''').replace('"','"').encode('ascii', 'xmlcharrefreplace')
【讨论】:
&amp;lt; 将被转义到&amp;lt;