파이썬에서 HTML을 탈출하는 가장 쉬운 방법은 무엇입니까?


137

cgi.escape는 하나의 가능한 선택처럼 보입니다. 잘 작동합니까? 더 나은 것으로 여겨지는 것이 있습니까?

답변:


176

cgi.escape괜찮습니다. 탈출 :

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

모든 HTML에 충분합니다.

편집 : ASCII가 아닌 문자가있는 경우 Craig 와 같이 다른 인코딩을 사용하는 다른 인코딩 된 문서에 포함시키기 위해 탈출하려고 합니다.

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

인코딩 된 인코딩을 사용하여 먼저 디코딩 data하는 것을 잊지 마십시오 unicode.

그러나 내 경험상 unicode처음부터 항상 작업하면 그러한 종류의 인코딩이 쓸모가 없습니다 . 문서 헤더에 지정된 인코딩으로 끝까지 인코딩하십시오 ( utf-8최대 호환성을 위해).

예:

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

또한 주목할 가치가 있습니다 (Greg 덕분에)는 추가 quote매개 변수 cgi.escape가 필요합니다. 그것은에 설정으로 True, cgi.escape도 (큰 따옴표 문자를 탈출 "당신은 XML / HTML 속성에 결과 값을 사용할 수 있도록).

편집 : 이는 cgi가 찬성 파이썬 3.2에서 사용되지 참고 것을 html.escape제외하고 동일한 작업을 수행, quoteTrue로 기본 설정됩니다.


7
HTML 속성 값에 텍스트가 사용될 때 따옴표를 이스케이프하려면 cgi.escape에 대한 추가 부울 매개 변수도 고려해야합니다.
Greg Hewgill

확실하게 : cgi.escape기능을 통해 신뢰할 수없는 모든 데이터를 실행하면 모든 알려진 XSS 공격으로부터 보호하기에 충분합니까?
Tomas Sedovic

@Tomas Sedovic : cgi.escape를 실행 한 후 텍스트를 넣을 위치에 따라 다릅니다. 루트 HTML 컨텍스트에 배치하면 예, 완전히 안전합니다.
nosklo 2019

{{Measures 12 Ω "H x 17 5/8"W x 8 7/8 "D. Imported.}}와 같은 입력은 어떻습니까? ascii가 아니므로 encode ()에서 예외가 발생합니다.
Andrew Kolesnikov

@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 바이트 열을 반환합니다.
nosklo

112

Python 3.2에는 htmlHTML 마크 업에서 예약 문자를 이스케이프하는 데 사용되는 새로운 모듈이 도입되었습니다.

그것은 하나의 기능을 가지고 있습니다 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?
2rs2ts

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
이것은 잘못된 종류의 탈출입니다. URL 인코딩 과 달리 HTML 이스케이프를 찾고 있습니다.
Chaosphere2112

7
그럼에도 불구하고-그것은 실제로 내가 찾던 것이 었습니다 ;-)
Brad

9

우수한 마크 업 안전 패키지도 있습니다.

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

markupsafe패키지는 잘 설계되었으며 IMHO 탈출을위한 가장 다재다능하고 파이썬적인 방법입니다. IMHO :

  1. 리턴 ( Markup)은 유니 코드에서 파생 된 클래스입니다 (예 :isinstance(escape('str'), unicode) == True
  2. 유니 코드 입력을 올바르게 처리합니다.
  3. 파이썬 (2.6, 2.7, 3.3 및 pypy)에서 작동합니다.
  4. 객체의 사용자 정의 메소드 (예 : __html__속성 이있는 객체 ) 및 템플릿 오버로드 ( __html_format__)를 고려합니다.

7

cgi.escape HTML 태그 및 문자 엔터티를 이스케이프하는 제한적인 의미에서 HTML을 이스케이프 처리하는 것이 좋습니다.

그러나 인코딩 문제를 고려해야 할 수도 있습니다. 인용하려는 HTML에 특정 인코딩에서 ASCII가 아닌 문자가있는 경우 인용 할 때 해당 문자를 현명하게 표현해야합니다. 아마도 당신은 그것들을 엔티티로 변환 할 수 있습니다. 그렇지 않으면 비 ASCII 문자가 손상되지 않도록 "소스"HTML과 포함 된 페이지간에 올바른 인코딩 변환이 수행되어야합니다.


3

순수한 파이썬 라이브러리는 텍스트를 html 텍스트로 안전하게 이스케이프하지 않습니다.

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

1
주문이 잘못되었습니다. &lt;의지로 탈출&amp;lt;
Jason S

@jason s 수정 해 주셔서 감사합니다!
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'
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.