cgi.escape wydaje się być jednym z możliwych wyborów. Czy to działa dobrze? Czy jest coś, co uważa się za lepsze?
cgi.escape wydaje się być jednym z możliwych wyborów. Czy to działa dobrze? Czy jest coś, co uważa się za lepsze?
Odpowiedzi:
cgi.escape
jest w porządku. Ucieka:
<
do <
>
do >
&
do &
To wystarczy dla całego HTML.
EDYCJA: Jeśli masz znaki inne niż ASCII, z których również chcesz uciec, aby włączyć je do innego zakodowanego dokumentu, który używa innego kodowania, jak mówi Craig , po prostu użyj:
data.encode('ascii', 'xmlcharrefreplace')
Nie zapomnij dekodowania data
do unicode
pierwszego, z wykorzystaniem co kodowania został zakodowany.
Jednak z mojego doświadczenia wynika, że ten rodzaj kodowania jest bezużyteczny, jeśli pracujesz z nim unicode
cały czas od początku. Po prostu zakoduj na końcu zgodnie z kodowaniem określonym w nagłówku dokumentu (utf-8
dla maksymalnej kompatybilności).
Przykład:
>>> cgi.escape(u'<a>bá</a>').encode('ascii', 'xmlcharrefreplace')
'<a>bá</a>
Warto również zwrócić uwagę (dzięki Greg) na dodatkowy quote
parametr cgi.escape
. Ustawiając ją na True
, cgi.escape
również wyłącza "
znak podwójnego cudzysłowu ( ), dzięki czemu można użyć wynikowej wartości w atrybucie XML / HTML.
EDYCJA: Zauważ, że cgi.escape został przestarzały w Pythonie 3.2 na korzyść html.escape
, który robi to samo, z wyjątkiem tego, że quote
domyślnie ma wartość True.
cgi.escape
funkcji, czy wystarczy, aby zabezpieczyć się przed wszystkimi (znanymi) atakami XSS?
cgi.escape(yourunicodeobj).encode('ascii', 'xmlcharrefreplace') == '{{Measures 12 Ω"H x 17 5/8"W x 8 7/8"D. Imported.}}'
- jak widać, wyrażenie zwraca ascii bytestring, ze wszystkimi znakami Unicode innymi niż ASCII zakodowanymi przy użyciu tabeli odwołań znaków xml.
W Pythonie 3.2 html
został wprowadzony nowy moduł, który służy do ucieczki znaków zastrzeżonych ze znaczników HTML.
Ma jedną funkcję 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()
domyślnie nie stosuje cudzysłowów (w przeciwieństwie do cgi.quote()
tego nie robi - i wyłącza tylko cudzysłowy, jeśli tak powiedziano). W związku z tym muszę jawnie ustawić opcjonalny parametr, aby wstrzyknąć coś do atrybutu html.escape()
, tj. Aby uczynić go niebezpiecznym dla atrybutów:t = '" onclick="alert()'; t = html.escape(t, quote=False); s = f'<a href="about.html" class="{t}">foo</a>'
escape()
nie wystarczy, aby atrybuty były bezpieczne. Innymi słowy, to nie jest bezpieczne:<a href=" {{ html.escape(untrusted_text) }} ">
href
jest ustawienie polityki bezpieczeństwa treści, która na to nie zezwala.
html.escape
pojedyncze i podwójne cudzysłowy.
Jeśli chcesz wyjść z kodu HTML w adresie URL:
Prawdopodobnie NIE jest to to, czego chciał OP (pytanie nie wskazuje jasno, w jakim kontekście ucieczka ma być używana), ale natywna biblioteka Pythona urllib ma metodę ucieczki z jednostek HTML, które muszą być bezpiecznie zawarte w adresie URL.
Oto przykład:
#!/usr/bin/python
from urllib import quote
x = '+<>^&'
print quote(x) # prints '%2B%3C%3E%5E%26'
Istnieje również doskonały pakiet zabezpieczający przed znacznikami .
>>> from markupsafe import Markup, escape
>>> escape("<script>alert(document.cookie);</script>")
Markup(u'<script>alert(document.cookie);</script>')
markupsafe
Pakiet jest dobrze zaprojektowane, i prawdopodobnie najbardziej wszechstronny i pythonowy droga o ucieczce, IMHO, ponieważ:
Markup
) jest klasą pochodzącą z Unicode (tjisinstance(escape('str'), unicode) == True
__html__
właściwością) i przeciążenia szablonów ( __html_format__
).cgi.escape
powinna być dobra ucieczka przed HTML w ograniczonym sensie ucieczki przed znacznikami HTML i jednostkami znakowymi.
Ale być może będziesz musiał również wziąć pod uwagę problemy z kodowaniem: jeśli HTML, który chcesz zacytować, zawiera znaki spoza ASCII w określonym kodowaniu, musisz również uważać, aby rozsądnie je przedstawiać podczas cytowania. Być może mógłbyś przekształcić je w byty. W przeciwnym razie należy upewnić się, że między „źródłowym” kodem HTML a stroną, na której jest osadzony, wykonywane są prawidłowe tłumaczenia kodowania, aby uniknąć uszkodzenia znaków spoza zestawu ASCII.
Brak bibliotek, czysty Python, bezpiecznie zapisuje tekst w tekście html:
text.replace('&', '&').replace('>', '>').replace('<', '<'
).encode('ascii', 'xmlcharrefreplace')
<
testament uciekł do&lt;
cgi.escape
rozszerzonyTa wersja jest ulepszona cgi.escape
. Zachowuje również spacje i nowe linie. Zwraca unicode
ciąg.
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"'
Nie jest to najłatwiejszy sposób, ale nadal prosty. Główna różnica w stosunku do modułu cgi.escape - nadal będzie działać poprawnie, jeśli już masz&
w tekście. Jak widać z komentarzy do tego:
Wersja 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
wersja regex
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)
W przypadku starszego kodu w Pythonie 2.7 można to zrobić za pośrednictwem BeautifulSoup4 :
>>> bs4.dammit import EntitySubstitution
>>> esub = EntitySubstitution()
>>> esub.substitute_html("r&d")
'r&d'