如果输入数据包含在标头字段参数中(例如标头的filename
参数Content-Disposition
),则可以对其进行编码(受这些规范email.utils.encode_rfc2231
的约束,这些规范定义了rfc2231 编码的变体)。
如果没有包含头字段参数,则似乎无法使用此方法。在这种情况下,最安全的选择可能是不包括输入,正如Julian Reschke 所写的那样;但是,如果您坚持包含输入,则可能需要尝试以下方法之一:
(这可能是不安全的,因为HTTP 不是符合 MIME 的协议,因此除非使用标头(并且可能即使使用了标头?),这些方法可能MIME-Version
无法正常用于 HTTP。)
单程...
要做到这一点,虽然它可能不是完全万无一失的(**编辑**:它*不是*万无一失的(当单独使用时);它接受 `\r\n\r\n`,它会终止标头并启动正文!因此需要处理`\r`和`\n`,除非前面有非`\r`/`\n`空格(如制表符或空格。)),是使用
`email.header`模块。这是专门为
rfc822 标头设计的(**edit**: 但是(似乎,因为电子邮件包曾经是几个单独的模块(
示例))
而不是 HTTP 标头!),所以似乎是这项工作的工具。这个 `Header` 类是用于编码 header *values*,而不是完整的 `Header-Name: value`,所以是这个工作的候选者(我们想要 vaidate 或逃避 value *only*)。
(提示:email
模块中的许多工具在使用其他 MIME 格式(编辑:可能还有类似 MIME)的东西时也很方便;模块中的东西也很方便cgi
,cgi.FieldStorage
特别是用于 HTTP 格式的解析。)
但是,只有当输入看起来是恶意的(似乎包含另一个(嵌入的)标头)email.header
时才会引发错误;但是,它似乎不会通过转义来处理无效输入(如果不是这样,请在评论中更正)。(该参数应该转义标头片段,返回有效输入,但是,它可能与用户代理(电子邮件、HTTP 等)没有那么好的兼容性;请参见此处(编辑:<a href="https://stackoverflow .com/a/1361646/541412>许多HTTP用户代理支持(不一定是类的编码参数(除了rfc2231编码之外,它似乎使用了一些特定于MIME的编码),但是)rfc5987charset
charset
email.header.Header
编码)。
例子:
import email.header
import re
def check_string_for_rfc822_header(s):
wip_header_component = str(email.header.Header(s))
if re.search(r'(\r?\n[\S\n\r]|\r[\S\r])', wip_header_component):
raise Exception
else:
return wip_header_component
# testing...
>>> check_string_for_rfc822_header("aaa")
"aaa"
>>> check_string_for_rfc822_header("a\r\nb")
"a\r\nb"
>>> check_string_for_rfc822_header("a\r\nb: c")
<error>
另一种方式...
要做到这一点,似乎只是简单地
删除 `\r` 和 `\n` 字符(但是,每个字符都是分开的;不要只删除出现的完整字符串 `\r\n`,因为这仍然会使这些未转义单独发生,并且许多(大多数?)HTTP utils 将分别接受它们中的每一个!)。类似地,我们可以通过替换 `\r\n`、`\r` 和 `\n` 来转义标头,并在它们的前面加上空格(这是转义标头的方法;请参阅
标准)。
但是,这种方法没有考虑到标准的细节(例如,rfc822 标头必须是 ACSII),这些标准本身可能是可利用的。
例子:
def remove_linebreakers(s):
return s.replace("\n", "").replace("\r", "")
# or...
import re
def remove_linebreakers(s):
re.sub(r'[\n\r]', '', s)
# testing...
>>> remove_linebreakers("aaa")
"aaa"
>>> remove_linebreakers("a\r\nb")
"ab"
>>> remove_linebreakers("a\r\nb: c")
"ab: c"
总之...
第一种方法似乎更好,但仅用于验证(不用于转义),除非它是参数值,在这种情况下使用
`email.utils.encode_rfc2231`对其进行转义。
例子:
# if we are not working with a header param value, the following...
# ...raises email.errors.HeaderParseError if input is poisonous when in a header
wip_header_component = str(email.header.Header('<input>'))
header_component = (raise_error() if re.search(r'(\r?\n[\S\n\r]|\r[\S\r])', wip_header_component) else wip_header_component)
# ...or if we *are* working with a header param value...
email.utils.encode_rfc2231('<input>', 'UTF-8')