【问题标题】:what characters are allowed in HTTP header values?HTTP 标头值中允许使用哪些字符?
【发布时间】:2018-05-21 02:34:01
【问题描述】:

在研究了HTTP/1.1 standard,特别是第 31 页和相关之后,我得出结论,任何 8 位八位字节都可以出现在 HTTP 标头值中。 IE。代码在 [0,255] 范围内的任何字符。

然而,我尝试过的 HTTP 服务器拒绝接收任何代码 > 127(或大多数 US-ASCII 不可打印字符)的内容。

这是标准中使用的语法摘录:

message-header = field-name ":" [ field-value ]
field-name     = token
field-value    = *( field-content | LWS )
field-content  = <the OCTETs making up the field-value and consisting of
                  either *TEXT or combinations of token, separators, and
                  quoted-string>

CR             = <US-ASCII CR, carriage return (13)>
LF             = <US-ASCII LF, linefeed (10)>
SP             = <US-ASCII SP, space (32)>
HT             = <US-ASCII HT, horizontal-tab (9)>
CRLF           = CR LF
LWS            = [CRLF] 1*( SP | HT )
OCTET          = <any 8-bit sequence of data>
CHAR           = <any US-ASCII character (octets 0 - 127)>
CTL            = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
TEXT           = <any OCTET except CTLs, but including LWS>

token          = 1*<any CHAR except CTLs or separators>
separators     = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\"
               | <"> | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT

quoted-string  = ( <"> *(qdtext | quoted-pair ) <"> )
qdtext         = <any TEXT except <">>
quoted-pair    = "\" CHAR

如您所见,field-content 可以是quoted-string,它是TEXT 的引用序列(即除"[0-8, 11-12, 14-31, 127] 范围内的值之外的任何8 位八位字节)或@987654332 @(\ 后跟 [0, 127] 范围内的任何值)。 IE。任何 8 位 char 序列都可以通过对其进行 en-quoting 并在特殊符号前加上 \ 来传递。

(请注意,标准不会以任何特殊方式对待NUL(0x00) char)

但是,很明显,要么我尝试的所有服务器都不符合标准,要么标准自 1999 年以来发生了变化,或者我无法正确阅读。

那么... HTTP 标头值中允许使用哪些字符以及为什么?

附:这一切背后的原因:我正在寻找一种在 HTTP 标头值中传递 utf-8 编码序列的方法(如果可能,无需额外编码)。

【问题讨论】:

  • 看起来没有人真正认真对待这部分标准。我最终得到了 url-encoding 标头值。
  • 注意field-names中的separators也需要编码。此外,如果您使用 WinHTTP——您必须在 field-name 中编码单引号,否则请求将失败。
  • 提示:RFC 2616 完全不相关。请参阅 RFC 7230。
  • RFC 7230 没有重写 RFC 2616 - 它澄清了它谢天谢地。 [tools.ietf.org/html/rfc7230#section-3.2] (§3.2) 使用标记 VCHAR 来指定允许的字段内容; VCHAR 在 [tools.ietf.org/html/rfc7230#section-1.2] (§1.2) 中定义为任何可见的 USASCII 字符。这个明确的标记消除了像 RFC 2616 那样花时间剔除不可见字符的需要,但没有扩展 1999/1982 的定义以包括 128-255。 OP 的问题是“HTTP 标头值中允许哪些字符以及为什么”。我已经回答了这个问题,并附有参考资料。
  • @C.M. - 是的,见rfc-editor.org/info/rfc2616

标签: http http-headers


【解决方案1】:

RFC 2616已过时,相关部分已替换为RFC 7230

NUL 字节不再允许在注释和引用字符串文本中, 并澄清了其中的反斜杠转义处理。这 引用对规则不再允许转义其他控制字符 比 HTAB。 标头字段中的非 US-ASCII 内容和原因短语 已被废弃并变得不透明(TEXT 规则已被删除)。 (第 3.2.6 节)

本质上,RFC 2616 默认为ISO-8859-1,这既不够用又不能互操作。因此,RFC 7230 已弃用字段值中的非 ASCII 八位字节。建议在此基础上使用转义机制(例如在RFC 8187 中定义,或纯 URI-percent-encoding)。

【讨论】:

  • RFC 2616 是否已过时?是的。这是否回答了 OP 的“HTTP 标头值中允许哪些字符以及为什么”的问题?没有。
  • 不推荐使用非 ASCII 字符。您可以发送它们,但不能保证收件人会按照您的期望进行操作。这就是规范所说的,这就是答案:-)
  • @JulianReschke 我终于有时间阅读 RFC 7230。我在 p3.2.6 中看不到任何非美国 ASCII 内容的“过时”——似乎它允许任何 0x80-0xFF 字符在quoted-string0x00-0x7F range 被淘汰了。 IE。根据此标准,只要您转义 0x00-0x7F 范围的“禁止”部分,您就可以在标头值中传递 utf-8 数据。我错了吗?
  • field-name 也可以包含'...如果我关心 MS 网络服务器,我想这种特殊情况将不得不保留在我的代码中。
  • “作为惯例,以“obs-”为前缀的 ABNF 规则名称表示由于历史原因出现的“过时”语法规则。 - greenbytes.de/tech/webdav/rfc7230.html#rfc.section.1.2.p.3
【解决方案2】:

看起来HTTP/1.1 specs 中有错误。正如您所指出的,第 4.2 节将字段内容描述为 OCTET:

field-content = 组成字段值的 OCTET

并且 OCTET 在 §2.2 中定义为:

OCTET = 任何 8 位数据序列

这些行是您得出应该允许八位字节 > 127 的结论的基础,当然我知道您是如何得出这个结论的。 §4.2 中提到的 OCTET 是误导性错误;它应该是 CHAR。

如果您从头开始阅读第 4.2 节(消息头),您会注意到以下指导:

HTTP 标头字段...遵循与 RFC 822 的第 3.1 节中给出的相同的通用格式

如果我们按照指示进行操作并转到RFC 822,特别是第 3.1.2 节(标头字段的结构),我们会了解到以下内容:

字段名必须由可打印的 ASCII 字符组成 (即,值介于 33. 和 126. 之间的字符, 小数,冒号除外)。 字段体可以由任何 ASCII 字符,CR 或 LF 除外。

因此,虽然 HTTP/1.1 是在 1999 年编写的,但他们使用 1982 年的定义来描述字段内容。 1982 年,字符 0-127 被称为“ASCII”,而 128-255 被称为“扩展 ASCII”。现在,在这个答案中,我不会涉及the food fight,这是在使用术语“扩展 ASCII”时引起的。 我将简单地向您指出 RFC 822 的 §3.3 以了解当时被视为“任何 ASCII 字符”的定义

CHAR = 任何 ASCII 字符(八进制:0-177,十进制:0.-127。)

所以你有它 - 确凿的证据。 “ASCII”在 1982 年停在 127 处。RFC 2616 §4.2 的书面段落部分为您指明了正确的方向,不幸的是后来在同一部分中误用了令牌 OCTET 导致您陷入了这个兔子洞。

【讨论】:

  • 那个解释是错误的,具体看greenbytes.de/tech/webdav/rfc2616.html#rfc.section.2.2.p.4>。
  • @GeekStocks - 你得出的结论不正确。 RFC 2616 确实允许非 ASCII 字符。由于我提到的原因,RFC 7230 已弃用它们(我应该知道,我是作者之一)。 “遵循格式”是格式起源的解释;这不是规范性参考。
  • @JulianReschke - 这真的很可笑。让我们看看我能不能把叉子放进去。 OP 声明“......我尝试拒绝接受任何代码 > 127 的服务器”。您自己的 RFC 2616 §2.2 链接显示了 为什么 OP 无法发送 128...255。它指出 US-ASCII 编码字符集由 ANSI X3.4-1986 [脚注 21] 定义。转至脚注 21。它是对 7 位美国标准代码的引用。现在,告诉我你如何得到一个只有 7 位的 >127 的数字? (放下麦克风) ;-p
  • 在 RFC 2616 中,“TEXT”的 ABNF 是“”。 OCTET 被定义为“”。除此之外,RFC 2616 非常清楚地指出:“*TEXT 的单词可能包含来自 ISO-8859-1 [22] 以外的字符集的字符,只有在根据 RFC 2047 [14] 的规则进行编码时。” - 所以来自 ISO-8859-1 的字符(它是 US-ASCII 的超集) 可以在 TEXT 中使用。我认为这很清楚。对 US-ASCII 的引用适用于表示“US-ASCII”的 ABNF 规则,而不适用于 OCTET。
  • 我只想知道 HTTP 标头值中的有效字符是什么。解开自引用 ABNF 文档的移动目标是没有效率的。我们需要一个带有单元测试的工作参考实现来澄清边缘情况以解决这个问题。为什么有这么多不同的方式来处理元数据?这是为网络开发人员创造工作保障还是为安全公司创造新的安全攻击面来修复?
猜你喜欢
  • 1970-01-01
  • 2011-06-15
  • 2010-12-30
  • 2011-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-07
相关资源
最近更新 更多