Python'da HTML'den kaçmanın en kolay yolu nedir?


137

cgi.escape olası bir seçenek gibi görünüyor. İyi çalışıyor mu? Daha iyi kabul edilen bir şey var mı?

Yanıtlar:


176

cgi.escapeiyidir. Kaçar:

  • < için &lt;
  • > için &gt;
  • & için &amp;

Bu, tüm HTML için yeterlidir.

DÜZENLEME: Ayrıca kaçmak istediğiniz ascii olmayan karakterleriniz varsa, Craig'in dediği gibi farklı bir kodlama kullanan başka bir kodlanmış belgeye dahil etmek için şunu kullanın:

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

Kod çözme unutmayın dataiçin unicodeher ne kodlanmış kodlayan kullanarak, ilk.

Ancak deneyimlerime göre unicode, başlangıçtan itibaren her zaman çalışırsanız bu tür bir kodlama işe yaramaz . Sonunda belge başlığında belirtilen kodlamaya kodlayın ( utf-8maksimum uyumluluk için).

Misal:

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

Ayrıca dikkate değer (teşekkürler Greg) ekstra quoteparametre cgi.escapealır. Olarak ayarlandığında True, cgi.escapeçift ​​tırnak karakterlerinden ( ") kaçar , böylece elde edilen değeri bir XML / HTML özniteliğinde kullanabilirsiniz.

DÜZENLEME: cgi.escape Python 3.2 lehine kaldırıldı unutmayın, html.escapebu quotevarsayılan olarak True dışında aynı yapar .


7
HTML öznitelik değerlerinde metin kullanıldığında, tırnaklardan kaçmak için cgi.escape için ek boole parametresi de dikkate alınmalıdır.
Greg Hewgill

Emin olmak için: Güvenilmeyen tüm verileri cgi.escapeişlev aracılığıyla çalıştırırsam , tüm (bilinen) XSS ataşmalarına karşı korumak için yeterli olur mu?
Tomas Sedovic

@Tomas Sedovic: İçinde cgi.escape'i çalıştırdıktan sonra metni nereye koyacağınıza bağlıdır. Kök HTML içeriğine yerleştirilirse, evet, tamamen güvendesiniz.
nosklo

{{Önlemler 12 Ω "Y x 17 5/8" G x 8 7/8 "D. İçe aktarıldı.}} Girdi ne olacak? Bu ascii değil, yani encode () size bir istisna atacak.
Andrew Kolesnikov

@Andrew Kolesnikov: Denediniz mi? cgi.escape(yourunicodeobj).encode('ascii', 'xmlcharrefreplace') == '{{Measures 12 &#937;"H x 17 5/8"W x 8 7/8"D. Imported.}}'- Gördüğünüz gibi, ifade ascii bytestring değerini döndürür ve tüm ascii olmayan unicode karakterleri xml karakter referans tablosu kullanılarak kodlanır.
nosklo

112

Python 3.2'de html, ayrılmış karakterleri HTML işaretlemesinden kaçmak için kullanılan yeni bir modül tanıtıldı.

Bir işlevi vardır 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;'

Ne olmuş quote=True?
2rs2ts

1
@SalmanAbbas Alıntıların kaçmamasından korkuyor musunuz? Not html.escape()Varsayılan olarak, tırnak kaçmayı yapar (aksine, cgi.quote()- ve böylece söyleseydim, sadece çift tırnak kaçar değil). Böylece, açıkça bir özniteliğe bir şey enjekte html.escape(), yani öznitelikler için güvensiz hale getirmek için isteğe bağlı bir parametre ayarlamak zorunda :t = '" onclick="alert()'; t = html.escape(t, quote=False); s = f'<a href="about.html" class="{t}">foo</a>'
maxschlepzig

@maxschlepzig Bence Salman'ın escape()öznitelikleri güvenli hale getirmek için yeterli olmadığını söylüyor . Başka bir deyişle, bu güvenli değil:<a href=" {{ html.escape(untrusted_text) }} ">
pianoJames

@pianoJames, anlıyorum. Bağlantı değerlerini etki alanına özgü bir anlamsal doğrulama olarak kontrol etmeyi düşünüyorum. Kaçmak gibi sözcüksel değil. Satır içi Java Komut Dosyasının yanı sıra, URL'ye daha fazla doğrulama yapılmadan (ör. Spam gönderenler nedeniyle) güvenilir olmayan kullanıcı girişinden bağlantılar oluşturmak istemezsiniz. Gibi özniteliklerde satır içi Java Komut Dosyasına karşı korumak için basit bir yöntem href , izin vermeyen bir İçerik Güvenliği İlkesi ayarlamaktır.
maxschlepzig

@pianoJames Güvenli, çünkü html.escapetek tırnak ve çift tırnak kaçıyor.
Flimm

11

Bir URL'deki HTML'den kaçmak istiyorsanız:

Bu muhtemelen OP'nin istediği DEĞİLDİR (soru, kaçmanın hangi bağlamda kullanılması gerektiğini açıkça belirtmez), ancak Python'un yerel kütüphanesi urllib , bir URL'ye güvenli bir şekilde dahil edilmesi gereken HTML varlıklarından kaçma yöntemine sahiptir.

Aşağıda bir örnek verilmiştir:

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

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

Dokümanları burada bulun


10
Bu yanlış bir kaçış şeklidir; URL kodlamasının aksine HTML kaçışlarını arıyoruz .
Chaosphere2112

7
Yine de - aslında aradığım şey buydu ;-)
Brad

9

Mükemmel markupsafe paketi de var .

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

markupsafePaket de tasarlanmıştır ve muhtemelen çok yönlü ve Pythonic yolu en IMHO, kaçan çünkü yaklaşık gitmek:

  1. return ( Markup), unicode'dan türetilen bir sınıftır (ör.isinstance(escape('str'), unicode) == True
  2. unicode girişi düzgün şekilde işler
  3. Python'da çalışır (2.6, 2.7, 3.3 ve pypy)
  4. özel nesne yöntemlerine (örneğin bir __html__özelliği olan nesneler ) ve şablon aşırı yüklemelerine ( __html_format__) saygı duyar .

7

cgi.escape HTML etiketlerinden ve karakter varlıklarından kaçma anlamında HTML'den kaçmak iyi olmalıdır.

Ancak kodlama sorunlarını da göz önünde bulundurmanız gerekebilir: alıntı yapmak istediğiniz HTML'de belirli bir kodlamada ASCII olmayan karakterler varsa, alıntı yaparken bunları anlamlı bir şekilde temsil ettiğinize de dikkat etmeniz gerekir. Belki onları varlıklara dönüştürebilirsiniz. Aksi takdirde, ASCII olmayan karakterlerin bozulmasını önlemek için "kaynak" HTML ile gömülü sayfa arasında doğru kodlama çevirilerinin yapıldığından emin olmalısınız.


3

Hiçbir kütüphane, saf python, metni html metnine güvenle kaçar:

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

1
Sizin sipariş, yanlış &lt;kaçan alacak&amp;lt;
Jason S

@jason s Düzeltme için teşekkürler!
Speedplane

1

cgi.escape Genişletilmiş

Bu sürüm geliştirildi cgi.escape. Ayrıca beyaz alanı ve satır sonlarını da korur. Bir unicodedize döndürür .

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;')

Örneğin

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

1

En kolay yol değil, ama yine de basit. Cgi.escape modülünden ana fark - &amp;metninizde zaten varsa düzgün çalışacaktır . Yorumlardan gördüğünüz gibi:

cgi.escape sürümü

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

normal ifade sürümü

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'deki eski kod için bunu BeautifulSoup4 üzerinden yapabilirsiniz :

>>> bs4.dammit import EntitySubstitution
>>> esub = EntitySubstitution()
>>> esub.substitute_html("r&d")
'r&amp;d'
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.