O cgi.escape parece ser uma opção possível. Isso funciona bem? Existe algo que é considerado melhor?
O cgi.escape parece ser uma opção possível. Isso funciona bem? Existe algo que é considerado melhor?
Respostas:
cgi.escape
está bem. Escapa:
<
para <
>
para >
&
para &
Isso é suficiente para todo o HTML.
EDIT: Se você possui caracteres não-ascii, também deseja escapar, para inclusão em outro documento codificado que usa uma codificação diferente, como Craig diz, basta usar:
data.encode('ascii', 'xmlcharrefreplace')
Não se esqueça de decodificar data
a unicode
primeira, usando qualquer codificação foi codificada.
No entanto, na minha experiência, esse tipo de codificação é inútil se você trabalhar unicode
o tempo todo desde o início. Basta codificar no final a codificação especificada no cabeçalho do documento ( utf-8
para obter compatibilidade máxima).
Exemplo:
>>> cgi.escape(u'<a>bá</a>').encode('ascii', 'xmlcharrefreplace')
'<a>bá</a>
Também digno de nota (obrigado Greg) é o quote
parâmetro extra cgi.escape
necessário. Com ele definido como True
, cgi.escape
também escapa chars de aspas duplas ( "
) para que você possa usar o valor resultante em um atributo XML / HTML.
EDIT: Observe que o cgi.escape foi preterido no Python 3.2 em favor de html.escape
, que faz o mesmo, exceto que o quote
padrão é True.
cgi.escape
função, é suficiente para proteger contra todos os attacs XSS (conhecidos)?
cgi.escape(yourunicodeobj).encode('ascii', 'xmlcharrefreplace') == '{{Measures 12 Ω"H x 17 5/8"W x 8 7/8"D. Imported.}}'
- como você pode ver, a expressão retorna ascii bytestring, com todos os caracteres unicode não-ascii codificados usando a tabela de referência de caracteres xml.
No Python 3.2, um novo html
módulo foi introduzido, usado para escapar caracteres reservados da marcação HTML.
Tem uma função 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()
, por padrão, as aspas escapadas (por outro lado, cgi.quote()
não escapam - e somente escapam aspas duplas, se solicitado). Assim, eu tenho que definir explicitamente um parâmetro opcional para injetar algo em um atributo com html.escape()
, ou seja, para torná-lo inseguro para os atributos:t = '" onclick="alert()'; t = html.escape(t, quote=False); s = f'<a href="about.html" class="{t}">foo</a>'
escape()
não é suficiente para tornar os atributos seguros. Em outras palavras, isso não é seguro:<a href=" {{ html.escape(untrusted_text) }} ">
href
é definir uma Política de Segurança de Conteúdo que não a permita.
html.escape
aspas simples e duplas.
Se você deseja escapar do HTML em um URL:
Provavelmente NÃO é isso que o OP queria (a pergunta não indica claramente em que contexto a fuga deve ser usada), mas a biblioteca nativa do Python urllib tem um método para escapar de entidades HTML que precisam ser incluídas em uma URL com segurança.
A seguir, um exemplo:
#!/usr/bin/python
from urllib import quote
x = '+<>^&'
print quote(x) # prints '%2B%3C%3E%5E%26'
Há também o excelente pacote de marcação segura .
>>> from markupsafe import Markup, escape
>>> escape("<script>alert(document.cookie);</script>")
Markup(u'<script>alert(document.cookie);</script>')
O markupsafe
pacote é bem projetado e provavelmente a maneira mais versátil e pitônica de escapar, IMHO, porque:
Markup
) é uma classe derivada do unicode (ou seja,isinstance(escape('str'), unicode) == True
__html__
propriedade) e sobrecargas de modelo ( __html_format__
).cgi.escape
deve ser bom escapar do HTML no sentido limitado de escapar das tags HTML e das entidades de caracteres.
Mas também é necessário considerar problemas de codificação: se o HTML que você deseja citar tiver caracteres não ASCII em uma codificação específica, também será necessário ter o cuidado de representá-los sensivelmente ao citar. Talvez você possa convertê-los em entidades. Caso contrário, você deve garantir que as traduções de codificação corretas sejam feitas entre o HTML "origem" e a página em que está incorporado, para evitar a corrupção de caracteres não ASCII.
Nenhuma biblioteca, python puro, escapa com segurança o texto para o texto html:
text.replace('&', '&').replace('>', '>').replace('<', '<'
).encode('ascii', 'xmlcharrefreplace')
<
escape será feito para&lt;
cgi.escape
estendidoEsta versão melhora cgi.escape
. Também preserva espaços em branco e novas linhas. Retorna uma unicode
string.
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"'
Não é o caminho mais fácil, mas ainda é direto. A principal diferença do módulo cgi.escape - ainda funcionará corretamente se você já possui &
seu texto. Como você vê nos comentários:
versão 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
versão 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)
Para código legado no Python 2.7, é possível fazê-lo via BeautifulSoup4 :
>>> bs4.dammit import EntitySubstitution
>>> esub = EntitySubstitution()
>>> esub.substitute_html("r&d")
'r&d'