如果输入数据包含在标头字段参数中(例如filename parameter of the Content-Disposition header),则可以使用email.utils.encode_rfc2231对其进行编码(受these specifications的约束,它定义了一个rfc2231 encoding 的变体)。
如果是不被包含一个头域参数,那么这个方法好像不能用。在这种情况下,最安全的选择可能是不包括输入,如Julian Reschke wrote;但是,如果您坚持包含输入,则可能需要尝试以下方法之一:
(这可能是不安全的,因为HTTP is not a MIME-compliant protocol,所以除非the MIME-Version header is used(甚至可能使用它?),这些方式可能无法正常工作用于HTTP。)
一种方式...
要做到这一点,虽然它可能不是完全万无一失的(**编辑**:它*不是*万无一失的(当单独使用时);它接受 `\r\n\r\n`,它会终止标头并启动正文!因此需要处理`\r`和`\n`,除非前面有非`\r`/`\n`空格(如制表符或空格。)),是使用
`email.header`模块。这是专门为
rfc822 headers设计的(**编辑**:但是(似乎,因为电子邮件包曾经是几个单独的模块(
example))
not for HTTP headers!),所以似乎是这项工作的工具.这个 `Header` 类是用来编码 header *values* 的,而不是完整的 `Header-Name: value`,所以是这个工作的候选者(我们想要 vaidate 或逃避 value *only*)。
(提示:email 模块中的许多工具在处理其他 MIME 格式(编辑:可能还有类似 MIME)的东西时也很方便;在cgi 模块,cgi.FieldStorage 特别是用于 HTTP 表单解析。)
然而,email.header 只会在输入看起来有恶意(似乎包含另一个(嵌入的)标头)时引发错误;但是,它似乎不会通过转义来处理 invalid 输入(如果不是这样,请在 cmets 中更正此问题)。 (charset 参数应该转义 header-fragment,返回 valid 输入,但是,它可能与用户代理(电子邮件、HTTP 等)没有那么好的兼容性;参见 here ( 编辑:rfc5987 编码)。
例子:
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>
另一种方式...
要做到这一点,似乎只是简单地
remove `\r` and `\n` characters (但是,每个都是单独的;不要只删除完整字符串 `\r\n` 的出现,因为这仍然会使这些单独出现时未转义,并且许多(大多数? ) HTTP utils 将分别接受它们中的每一个!)。类似地,我们可以通过替换 `\r\n`、`\r` 和 `\n` 来转义标头,并在它们的前面加上空格(这是转义标头的方法;请参阅
the standard)。
但是,这种方法没有考虑到标准的细节(例如,rfc822 标头must be 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')