Как я могу экранировать * все * символы в соответствующие им имена и номера HTML-объектов в Python? - PullRequest
2 голосов
/ 03 апреля 2019

Я хотел закодировать строку в соответствующие html-объекты, но, к сожалению, я не смог. Как я уже сказал в заголовке вопроса, я хочу, чтобы все символов в строке были преобразованы в соответствующие им html-сущности (как числа, так и имена). Так что согласно документации . Я попробовал:

In [31]: import html

In [32]: s = '<img src=x onerror="javascript:alert("XSS")">'

In [33]: html.escape(s)
Out[33]: '&lt;img src=x onerror=&quot;javascript:alert(&quot;XSS&quot;)&quot;&gt;'

Но я хочу, чтобы все символы были преобразованы, а не только «<», «>», «&» и т. Д. А также html.escape дает только html-сущность имен , а не цифры, но я хочу и то и другое.

Но на удивление html.unescape эскалирует все сущности в соответствующие им символы.

In [34]: a = '<img src=x onerror="&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#000005
    ...: 8&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041">'

In [35]: html.unescape(a)
Out[35]: '<img src=x onerror="javascript:alert(\'XSS\')">' 

Так я могу сделать то же самое с html.escape?

Я действительно удивлен, почему все ресурсы в Интернете для кодирования и декодирования html-сущностей не кодируют все символы, а также функция php htmlspecialchars() этого не делает. И я не хочу писать все html номера сущностей из здесь символ за символом.

1 Ответ

2 голосов
/ 03 апреля 2019

Вам на самом деле не нужна специальная функция для того, что вы делаете, потому что нужные вам цифры - это всего лишь кодовые точки Unicode рассматриваемых символов.

ord делает в значительной степени то, что вы хотите:

 def encode(s):
     return ''.join('&#{:07d};'.format(ord(c)) for c in s)

Эстетически, я предпочитаю шестнадцатеричное кодирование:

 def encode(s):
     return ''.join('&#x{:06x};'.format(ord(c)) for c in s)

Особенность html.escape и html.unescape в том, что они поддерживают именованные объекты в дополнение к числовым. Цель экранирования обычно состоит в том, чтобы превратить вашу строку во что-то, что не имеет символов, характерных для анализатора HTML, поэтому escape заменяет только несколько символов. То, что вы делаете, гарантирует, что все символы в строке являются ASCII в дополнение к этому.

Если вы хотите принудительно использовать именованные сущности везде, где это возможно, вы можете проверить отображение html.entities.codepoint2name после применения ord к символам:

def encode(s):
    return ''.join('&{};'.format(codepoint2name.get(i, '#{}'.format(i))) for i in map(ord, s))
...