在Python中转义HTML的最简单方法是什么?


Answers:


175

cgi.escape很好 它逃脱了:

  • <&lt;
  • >&gt;
  • &&amp;

对于所有HTML而言,这就足够了。

编辑:如果您有非ASCII字符,您还想转义,以便包含在使用不同编码的另一个编码文档中,如Craig所说,只需使用:

data.encode('ascii', 'xmlcharrefreplace')

不要忘了解码dataunicode第一,使用任何编码它编码的。

但是根据我的经验,如果您unicode从头开始一直都在工作,那么这种编码是没有用的。只需在文档头中指定的编码末尾进行编码(utf-8以实现最大兼容性)。

例:

>>> cgi.escape(u'<a>bá</a>').encode('ascii', 'xmlcharrefreplace')
'&lt;a&gt;b&#225;&lt;/a&gt;

另外值得一提的(感谢Greg)是额外的quote参数cgi.escape。将其设置为时Truecgi.escape还转义双引号字符("),因此您可以在XML / HTML属性中使用结果值。

编辑:请注意,cgi.escape已在Python 3.2中弃用,转而使用html.escape,它的功能相同,但quote默认情况下为True。


7
当在HTML属性值中使用文本时,也应考虑使用cgi.escape的附加布尔值来转义引号。
格雷格·休吉尔

只是要确保:如果我通过该cgi.escape功能运行所有不受信任的数据,是否足以抵御所有(已知)XSS攻击?
Tomas Sedovic

@Tomas Sedovic:取决于您在其中运行cgi.escape之后将文本放置在何处。如果放在根HTML上下文中,那么可以,您是完全安全的。
nosklo 2010年

关于像{{措施12Ω“H×17 5/8”宽x 8 7/8" d进口}}这不是ASCII码,所以编码()将在你抛出一个异常输入什么
安德鲁·科列斯尼科夫

@Andrew Kolesnikov:您尝试过吗?cgi.escape(yourunicodeobj).encode('ascii', 'xmlcharrefreplace') == '{{Measures 12 &#937;"H x 17 5/8"W x 8 7/8"D. Imported.}}'-如您所见,该表达式返回ascii字节串,并使用xml字符引用表对所有非ascii unicode字符进行编码。
2010年

111

在Python 3.2中,新 html,引入模块,该模块用于从HTML标记转义保留字符。

它具有一个功能escape()

>>> import html
>>> html.escape('x > 2 && x < 7 single quote: \' double quote: "')
'x &gt; 2 &amp;&amp; x &lt; 7 single quote: &#x27; double quote: &quot;'

quote=True
2013年

1
@SalmanAbbas您担心引号不能转义吗?请注意,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>'
maxschlepzig

@maxschlepzig我认为Salman所说escape()的不足以使属性安全。换句话说,这并不安全:<a href=" {{ html.escape(untrusted_text) }} ">
pianoJames

@pianoJames,我明白了。我考虑检查链接值是特定于域的语义验证。没有像逃避这样的词汇。除了内联Java脚本外,您真的不想在没有进一步的特定于URL的验证的情况下(例如由于垃圾邮件发送者)从不受信任的用户输入创建链接。防止诸如属性之类的内联Java脚本的简单方法href 是设置不允许它的内容安全策略。
maxschlepzig

@pianoJames这是安全的,因为html.escape它会转义单引号和双引号。
Flimm

11

如果您希望在URL中转义HTML:

这可能不是OP想要的(问题并没有明确指出转义是在哪种上下文中使用的),但是Python的本机库urllib有一种方法可以转义需要安全包含在URL中的HTML实体。

以下是一个示例:

#!/usr/bin/python
from urllib import quote

x = '+<>^&'
print quote(x) # prints '%2B%3C%3E%5E%26'

在这里找到文件


10
这是错误的转义;我们正在寻找HTML转义,而不是URL编码
Chaosphere2112 2013年

7
尽管如此-这实际上是我真正想要的;-)
Brad

9

还有出色的markupsafe软件包

>>> from markupsafe import Markup, escape
>>> escape("<script>alert(document.cookie);</script>")
Markup(u'&lt;script&gt;alert(document.cookie);&lt;/script&gt;')

markupsafe程序包经过精心设计,并且可能是逃避转义的最通用,最Python化的方法,恕我直言,因为:

  1. return(Markup)是从unicode派生的类(即isinstance(escape('str'), unicode) == True
  2. 它可以正确处理unicode输入
  3. 它适用于Python(2.6、2.7、3.3和pypy)
  4. 它尊重对象(即具有__html__属性的对象)和模板重载(__html_format__)的自定义方法。

7

cgi.escape 从转义HTML标记和字符实体的有限意义上讲,应该可以逃脱HTML。

但是,您可能还必须考虑编码问题:如果要引用的HTML在特定的编码中包含非ASCII字符,那么还必须注意在引用时要合理地表示这些字符。也许您可以将它们转换为实体。否则,您应确保在“源” HTML和嵌入页面之间进行正确的编码转换,以避免损坏非ASCII字符。


3

没有库,纯python,可以安全地将文本转义为html文本:

text.replace('&', '&amp;').replace('>', '&gt;').replace('<', '&lt;'
        ).encode('ascii', 'xmlcharrefreplace')

1
您的订购错了,&lt;遗嘱将转移到&amp;lt;
Jason S

@jason的谢谢修复!
speedplane

1

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'&emsp;').\
           replace(u'  ', u' &nbsp;')

例如

>>> escape_html('<foo>\nfoo\t"bar"')
u'&lt;foo&gt;<br />foo&emsp;&quot;bar&quot;'

1

不是最简单的方法,但仍然很简单。与cgi.escape模块的主要区别-如果您已经&amp;在文本中使用了它,它仍然可以正常工作。从评论中可以看到:

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("&", "&amp;") # Must be done first!
    s = s.replace("<", "&lt;")
    s = s.replace(">", "&gt;")
    if quote:
        s = s.replace('"', "&quot;")
    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 = {
        '<': '&gt;',
        '>': '&lt;',
        '&': '&amp;',
        '"': '&quot;', # should be escaped in attributes
        "'": '&#39'    # should be escaped in attributes
    }
    quote_pattern = re.compile(QUOTE_PATTERN)
    return re.sub(quote_pattern, lambda x: replace_with[x.group(0)], word)

0

对于Python 2.7中的旧代码,可以通过BeautifulSoup4做到:

>>> bs4.dammit import EntitySubstitution
>>> esub = EntitySubstitution()
>>> esub.substitute_html("r&d")
'r&amp;d'
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.