【问题标题】:security for http headershttp标头的安全性
【发布时间】:2011-11-22 17:37:47
【问题描述】:

我们希望在发送 HTTP 标头之前仔细检查它们的安全性。显然我们不能允许 '\r' 或 '\n' 出现,因为这会允许内容注入。

我在这里只看到两个选项:

  1. 在换行符处截断值。
  2. 从标头值中去除无效字符。

此外,从阅读RFC2616 来看,似乎只有 ascii 可打印字符对 http 标头值有效,我是否也应该对其他 154 个可能的无效字节遵循相同的策略?

或者,有没有关于这个主题的权威现有技术?

【问题讨论】:

    标签: security http http-headers escaping base64


    【解决方案1】:

    这种攻击称为“标头拆分”或"response splitting"

    该 OWASP 链接指出删除 CRLF 是不够的。 \n 可能同样危险。

    要成功执行漏洞利用,应用程序必须允许在标头中输入包含 CR(回车,也由 0x0D 或 \r 给出)和 LF(换行,也由 0x0A 或 \n 给出)字符。

    (我不知道为什么 OWASP(和其他页面)将 \n 列为漏洞,或者这是否仅适用于预解码的查询片段。)

    在任何尝试设置包含在标头键或值中的规范不允许的字符的标头时提供 500 是完全合理的,并且将允许您识别日志中的攻击性请求。当你知道你的过滤器失败时快速失败是一个很好的策略。

    如果您使用的语言允许,您可以将 HTTP 响应对象包装在一个在看到错误标头时引发异常的对象中,或者您可以更改响应对象以进入无效状态,设置响应代码到500,然后关闭响应体流。

    编辑:

    我应该去除非 ASCII 输入吗?

    我更喜欢在接收可信输入的层中进行这种规范化,除非在实体转义将纯文本转换为 HTML 转义的情况下,存在明确的类型转换。如果是类型转换,我会在需要输出类型时进行,但如果不是类型转换,我会尽早进行,以便该类型数据的所有消费者看到一致的值。我发现这种方法使调试和文档编制变得更容易,因为输入处理下面的层永远不必担心非规范化的输入。

    在实现 HTTP 响应包装器时,我会使其在 all 非 ascii 字符(包括非 ASCII 换行符,如 U+85、U+2028、U+2029)上失败,然后制作确保我的应用程序测试包括对每个第三方 URL 输入的测试,以确保在 Location 到达 setHeader 之前,任何 Location 标头都正确编码,对于可能到达请求标头的其他输入也是如此。

    如果您的 cookie 包含用户 ID 或电子邮件地址等内容,我会确保用于测试的虚拟帐户包含一个用户 ID 或电子邮件地址包含非 ASCII 字母的虚拟帐户。

    【讨论】:

    • 我们应该去掉不可打印的字符吗?
    • 感谢您的详细回复,但我不是特别了解这个。您似乎建议同时剥离所有非 ascii 字符,但要确保非 ascii cookie 起作用。似乎一个会排除另一个。
    • 关于您假设的请求包装器:您知道任何以这种方式运行的库吗?如果我理解正确,您将在 setHeader 方法期间执行这些检查,以便尽早失败。
    • @bukzor,很多库抛出IllegalArgumentException,像java.nio 这样的库在被非法标记移动到不一致的状态时抛出IllegalStateException,番石榴集合构建器在运行时异常快速失败由于无效的成员或重复的键,导致对象无法构建,java 的 fail-fast iterators 当他们意识到他们已进入无法恢复的不一致状态时抛出 ConcurrentModificationException
    • @bukzor,我相信ObjectInputStreamObjectOutputStream 在外部化/反序列化失败意味着后续操作很有可能在流上运行时也会进入无效状态只是部分建造/消耗。
    【解决方案2】:

    简单地删除新行\n 将阻止HTTP Response Splitting。即使在 RFC 中使用 CRLF 作为分隔符,所有浏览器都可以单独识别新行。

    您仍然需要担心set-cookiecontent-type 中的用户内容。这些元素中的属性使用; 分隔,攻击者可能会将内容类型更改为 UTF-7 并绕过您对 IE 用户(并且仅限 IE 用户)的 XSS 保护。攻击者也有可能创建一个新的 cookie,这引入了会话固定的可能性。

    【讨论】:

    • 能否多扩展一下UTF7相关的XSS,或者给个参考?
    • @Rook,我相信如果你控制了Content-type header,你可以对IE以外的浏览器进行UTF-7攻击。在未指定编码时,只有 IE 会猜测 UTF-7,但其他浏览器仍应尊重 UTF-7 标头。 ha.ckers.org 在自动检测的浏览器中包含“Netscape 8.1 in IE 渲染引擎模式”,并强烈暗示其他浏览器尊重标头。
    • @bukzor,请参阅cheat sheet中标题为“UTF-7 编码”的部分:<HEAD><META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=UTF-7"> </HEAD>+ADw-SCRIPT+AD4-alert('XSS');+ADw-/SCRIPT+AD4-
    • @Mike Samuel 太好了,您是否尝试过在 Firefox 或 chrome 上执行该代码片段? UTF-7 用于 SMTP,而不是 HTTP,IE 是唯一支持它的,他们在 IE9 中删除了 UTF-7 内容嗅探。 xss 备忘单已经用了 5 年了,几乎没用。
    • @Rook。我还没有在最近构建的非 MS 浏览器上尝试过它。我同意 UTF-7 的目的。我的理解是浏览器在某些时候使用 byte[]->UTF-16[] 解码的标准库,并且 UTF-7 在许多这些库中都可用。如果较新的浏览器对编码持怀疑态度,那就太好了,但是我们这些从事框架工作的人需要支持想要支持 IE 6 和旧版本 Safari 的应用程序开发人员。
    【解决方案3】:

    标题字段中允许使用非 ASCII 字符,尽管规范并没有明确说明它们的含义;所以由发送者和接收者就他们的语义达成一致。

    是什么让你不这么认为?

    【讨论】:

    • 标头定义为 TEXT,TEXT 是“除 CTL 外的任何 OCTET,但包括 LWS”。 CTL 是“(八位字节 0 - 31)和 DEL (127)”。这似乎允许八进制数 > 127,但我怀疑这是有意的。
    • 我看到通过“编码字”允许非 iso-8859-1 编码,但它继续说“只有可打印和空白字符数据应该使用这种方案进行编码”,在这种情况下,我宁愿只使用 ascii。
    • bukzor:我认为这是有意的,我知道它偶尔会被使用。还需要中间体让所有 8 位都通过,否则将来某个时间将无法使用 UTF-8 作为标头字段编码。
    • 我认为 utf8 已经出局了,因为明确禁止使用八位字节 0-31 和 127。
    • bukzor:不,那只是意味着您不能拥有 CTL 或 DEL。这不会影响角色曲目的其余部分。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-11
    • 2016-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-10
    相关资源
    最近更新 更多