HTTP/2笔记之错误处理和安全
零。前言
这里整理了一下错误和安全相关部分简单记录。
一。HTTP/2错误
1. 错误定义
HTTP/2定义了两种类型错误:
- 导致整个连接不可使用的错误为连接错误(connection error)
- 单独出现在单个连接上的错误为流错误(stream error)
2. 错误代码
错误代码,32位正整数表示错误原因,RST_STREAM和GOAWAY帧中包含。
未知或不支持的错误代码可以选择忽略,或作为INTERNAL_ERROR错误对待都可以。
3. 连接错误处理
一般来讲连接错误很严重,会导致处理进程无法进行下去,或影响到整个连接的状态。
- 终端一旦遇上连接错误,需第一时间在最后一个可用流上发送包含错误原因GOAWAY帧过去,然后关闭连接
- GOAWAY有可能不被对端成功接收到,若成功接收可获得连接被终止的原因
- 终端可在任何时间终止连接,也可以把流错误作为连接错误对待。但都应该在关闭连接之前发送一个GOAWAY帧告知对方
4. 流错误
一般来讲具体流上的流错误不会影响到其它流的处理。
- 终端检测到流错误,需要发送一个RST_STREAM帧,其包含了操作到错误流标识符
- RST_STREAM应当是发送错误流最后一个帧,内含错误原因。
- 发送方在发送之后,需要准备接收对端将要或即将发送过来的帧数据,处理方式就是忽略之,除非是可以修改连接状态帧
- 一般来讲,终端不应该发送多个RST_STREAM帧,但若在一个往返时间之后已关闭的流上能够继续接收帧,则需要发送再次发送一个RST_STREAM帧,处理这种行为不端的实现。
- 终端在接收到RST_STREAM帧之后,不能响应一个RST_STREAM帧,避免死循环
5. 连接终止
TCP连接被关闭或重置时仍有处于"open"或"half closed"的流将不能自动重试。
二。HTTP/2安全注意事项
1. 跨协议攻击
跨协议攻击,字面上理解就很简单,比如攻击者构建HTTP/1.1请求直接转发给仅仅支持HTTP/2的服务器,以期待获取攻击效果。
这里有一篇讲解跨协议攻击的文章: http://www.freebuf.com/articles/web/19622.html
TLS的加密机制使得攻击者很难获得明文,另外TLS的ALPN协议扩展可以很轻松处理请求是否需要作为HTTP/2请求进行处理,总之可有效阻止对基于TLS的其它协议攻击。
基于标准版TCP没有TLS和ALPN的帮忙,客户端所发送连接序言前缀为PRI字符串用来混淆HTTP/1.1服务器,但对其它协议没有提供保护,仅限于此。但在处理时,若接收到HTTP/1.1的请求,没有包含Upgrade升级字段,则需要认为是一个跨协议攻击。
总之,程序要尽可能的健壮,容错,针对非法的请求,直接关闭对方连接。
2. 中介端数据转换封装的攻击
中介所做的HTTP/1.1和HTTP/2之间转换,会存在攻击点:
- HTTP/2头字段名称编码允许使用HTTP/1.1没有使用到的头字段名称,中介在转换HTTP/2到HTTP/1.1时就容易出现包含非法请求头字段HTTP/1.1数据。
- HTTP/2允许头字段值可以是非法值,诸如回车(CR, ASCII 0xd), 换行 (LF, ASCII 0xa), 零字符 (NUL, ASCII 0x0),这在逐字解析实现时是一个风险。
解决方式,一旦发现非法头字段名称,以及非法头字段值,都作为不完整、残缺数据对待,或丢弃,或忽略。
3. 推送内容的缓存
推送内容有保证的服务器提供,是否缓存由头字段Cache-Control控制。
但若服务器上多租户形式(SAAS),每一个租户使用一小部分URL空间,比如 tenant1.domain.com,tenant2.domain.com,服务器需要确保没有授权的租户不能够推送超于预期的资源,覆盖已有内容。
原始服务器没有被授权使用推送,既不能够违规发送推送,也不能够被缓存。
4. 拒绝服务攻击注意事项
- HTTP/2因为要为流、报头压缩、流量控制等特性占用资源较多,因此针对每一个连接的内存分配要设置限额,否则很少的连接占满内存,无法正常服务
- 针对单个连接,规范对PUSH_PROMISE帧数量没有约束,但客户端需要设置一个上限值,这也是确定需要维护的"reserved (remote)"状态的数量,超出限额需要报ENHANCE_YOUR_CALM类型流错误
- SETTINGS帧有可能会被滥用导致对端需要花费时间解析处理设置限制等,滥用情况包括包含未定义的参数,以及同一个参数多次出现等,类似于WINDOW_UPDATE和PRIORITY帧都会存在滥用的情况;这些帧被滥用导致资源耗费情况严重
- 大量小帧或空帧一样会被滥用,但又符合逻辑,耗费服务器资源在处理报文头部上面。比如空负载DATA帧,以及用于携带报文头部数据的CONTINUATION帧,都属于安全隐患
- 报头压缩存在潜在风险,也会被滥用,详情可参考HPACK协议第七章: http://http2.github.io/http2-spec/compression.html#Security
- 终端中途发送的SETTINGS帧所定义参数不是立即可以生效的,这会导致对端在实际操作时可能会超过最新的限制。建议直接在连接建立时在连接序言内包含设置值,就算如此,客户端也会存在超出服务器端连接序言中所设置的最新限定值。
总之,诸如SETTINGS帧、小帧或空帧,报头压缩被合理滥用时,表明上看符合逻辑,会造成资源过度消耗。这需要服务器端监控跟踪到此种行为,并且设置使用数量的上限,一旦发现直接报ENHANCE_YOUR_CALM类型连接错误。
5. 报头块大小限制
报头块过大导致实现需要维护大量的状态开销。另外,根据报头字段进行路由的情况,若此报头字段出现在一系列报头块帧的最后一个帧里面,可能会导致无法正常路由到目的地。若被缓存会导致耗费大量的内存。这需要设置SETTINGS_MAX_HEADER_LIST_SIZE参数限制报头最大值,以尽可能的避免出现以上情况。
服务器一旦接收到超过报头限制请求,需要响应一个431(请求头过大) HTTP状态码,客户端呢可直接丢掉响应。
6. 压缩使用的安全隐患
- 针对安全通道,不能使用同一个压缩字典压缩保密的关键数据和易受攻击者控制的数据
- 来源数据不能确定为完全可靠,就不应该使用压缩机制
- 通用流的压缩不能在基于TLS的HTTP/2上使用这一部分,可参考 http://http2.github.io/http2-spec/compression.html#Security
7. 填充使用的安全隐患
一般来讲,填充可用来混淆帧的真实负载长度,稍加保护,降低攻击的可能性。但若不当的填充策略:固定填充数、可轻松推导出填充规则等情况都会降低保护的力度,都有可能会被攻击者破解。
中介设备应该保留DATA帧的填充(需要避免如上所述一些情况),但可丢弃HEADERS和PUSH_PROMISE帧的填充。
三。TLS
HTTP/2加密建立在TLS基础,关于TLS,维基百科上有解释: http://zh.wikipedia.org/wiki/%E5%82%B3%E8%BC%B8%E5%B1%A4%E5%AE%89%E5%85%A8%E5%8D%94%E8%AD%B0
摘取一张图,可说明基于ALPN协议扩展定义的协商流程:
其它要求:
- 只能基于TLS >= 1.2版本。目前TLS 1.3为草案版本,正式版本目前尚未可知。目前只有TLS 1.2可选。
- 必须支持Server Name Indication (SNI) [TLS-EXT]扩展,客户端在连接协商阶段需要携带上域名
- 基于TLS 1.3或更高版本构建,仅需要支持SNI扩展。TLS 1.2要求较多
- 基于TLS 1.2构建
- 必须禁用压缩机制。不恰当压缩机制会导致信息外露,HTTP/2报头有压缩机制
- 必须禁用重新协商机制。终端对待TLS 1.2重新协商作为PROTOCOL_ERROR类型连接错误对待;密码套件加密次数限制导致连接一直挂起等待不可用
- 终端可以通过重新协商提供对客户端凭证保护功能在握手期间,重新协商必须发生在发送连接序言之前进行。服务器当看到重新协商请求时应该请求客户端证书在连接建立后
- 当客户端请求受保护的特定资源时,服务器可以响应HTTP_1_1_REQUIRED错误,可有效阻止重新协商机制
四。小结
这里简单记录HTTP/2错误和安全相关事项,本系列规范学习到此告一段落。