17. 安全注意事项
本节旨在告知开发者, 信息提供者和用户有关 HTTP 语义及其用于在 Internet 上传输信息时的已知安全问题. 与缓存相关的注意事项见 [CACHING] 的 Section 7, 与 HTTP/1.1 消息语法和解析相关的注意事项见 [HTTP/1.1] 的 Section 11.
下面的注意事项列表并不详尽. 与 HTTP 语义相关的大多数安全问题, 关注的是保护服务器端应用程序 (HTTP 接口背后的代码), 保护用户代理对通过 HTTP 接收的内容的处理, 或一般意义上的 Internet 安全使用, 而不是协议本身的安全. URI 是 HTTP 操作的基础, 其安全注意事项见 [URI] 的 Section 7. 各类组织维护着关于 Web 应用安全的专题信息以及当前研究链接 (例如 [OWASP]).
17.1. 建立权威性
HTTP 依赖 "authoritative response" 的概念: 由目标 URI 中标识的源服务器确定 (或按其指示确定) 的响应, 即在响应消息生成时, 根据目标资源当时的状态, 对该请求最适当的响应.
当 authority 组成部分使用注册名称时, "http" URI scheme (Section 4.2.1) 依赖用户的本地名称解析服务来确定在哪里可以找到权威响应. 这意味着, 对用户网络主机表, 缓存名称或名称解析库的任何攻击, 都会成为攻击 "http" URI 权威性建立过程的途径. 同样, 用户选择的 Domain Name Service (DNS) 服务器以及它获取解析结果所依赖的服务器层级, 都可能影响地址映射的真实性; DNS Security Extensions (DNSSEC, [RFC4033]) 是提升真实性的一种方式, 通过更安全的传输协议发起 DNS 请求的各种机制也是如此.
此外, 获得 IP 地址之后, 为 "http" URI 建立权威性仍然容易受到 Internet Protocol 路由攻击.
"https" scheme (Section 4.2.2) 旨在防止 (或至少揭示) 许多这类针对权威性建立过程的潜在攻击, 前提是协商得到的连接受到保护, 且客户端正确验证通信服务器的身份与目标 URI 的 authority 组成部分匹配 (Section 4.3.4). 正确实现这种验证可能很困难 (见 [Georgiev]).
给定源服务器的权威性可以通过协议扩展委派; 例如 [ALTSVC]. 同样, 被认为对某个连接具有权威性的服务器集合, 可以通过 [RFC8336] 这样的协议扩展改变.
由非权威来源提供响应, 例如共享代理缓存, 通常有助于提升性能和可用性, 但前提是该来源可信, 或不可信的响应可以被安全使用.
遗憾的是, 向用户传达权威性可能很困难. 例如, "phishing" 是对用户权威性感知的攻击, 这种感知可能通过在超文本中呈现相似品牌而被误导, 也可能借助 userinfo 混淆 authority 组成部分 (见 Section 4.2.1). 用户代理可以通过以下方式降低 phishing 攻击的影响: 让用户在执行操作前能够轻松检查目标 URI, 在存在 userinfo 时醒目地区分 (或拒绝) 它, 以及当引用文档来自未知或不可信来源时不发送已存储的凭据和 cookie.
17.2. 中间方的风险
HTTP 中间方天然处于路径上攻击的位置. 中间方运行所在系统一旦被攻陷, 可能导致严重的安全和隐私问题. 中间方可能访问与安全相关的信息, 关于个人用户和组织的个人信息, 以及属于用户和内容提供者的专有信息. 被攻陷的中间方, 或在实现或配置时未考虑安全和隐私问题的中间方, 可能被用于实施范围广泛的潜在攻击.
包含共享缓存的中间方尤其容易受到缓存投毒攻击, 如 [CACHING] 的 Section 7 所述.
实现者需要考虑其设计和编码决策的隐私与安全影响, 也需要考虑其提供给运营者的配置选项 (特别是默认配置) 的影响.
中间方的可信程度不会高于运行它们的人和政策; HTTP 无法解决这个问题.
17.3. 基于文件名和路径名的攻击
源服务器经常使用本地文件系统来管理从目标 URI 到资源表示的映射. 大多数文件系统并非设计用于防御恶意文件名或路径名. 因此, 源服务器在将目标资源映射到文件, 文件夹或目录时, 需要避免访问对系统具有特殊意义的名称.
例如, UNIX, Microsoft Windows 和其他操作系统使用 ".." 作为路径组成部分来表示当前目录的上一级, 并使用具有特殊名称的路径或文件名向系统设备发送数据. 其他类型的存储系统中也可能存在类似命名约定. 同样, 本地存储系统在处理无效或意外字符, 分解字符的重组, 以及大小写不敏感名称的大小写规范化时, 往往偏向用户友好而非安全.
基于这类特殊名称的攻击通常集中于拒绝服务 (例如让服务器从 COM 端口读取) 或披露本不应被服务的配置文件和源文件.
17.4. 基于命令, 代码或查询注入的攻击
源服务器经常使用 URI 中的参数来标识系统服务, 选择数据库条目或选择数据源. 然而, 请求中收到的数据不能被信任. 攻击者可以构造任何请求数据元素 (method, target URI, header fields 或 content), 使其中的数据在传递给命令调用, 语言解释器或数据库接口时被误解为命令, 代码或查询.
例如, SQL 注入是一种常见攻击, 其中额外的查询语言被插入目标 URI 或头字段的某个部分 (例如 Host, Referer 等). 如果收到的数据被直接用于 SELECT 语句, 查询语言可能被解释为数据库命令, 而不是简单的字符串值. 尽管这类实现漏洞很容易预防, 但它极其常见.
一般来说, 资源实现应当避免在会被处理或解释为指令的上下文中使用请求数据. 参数应当与固定字符串比较, 并根据比较结果采取行动, 而不是传递给未准备好处理不可信数据的接口. 不是基于固定参数的接收数据, 应当被仔细过滤或编码, 以免被误解.
当请求数据被存储后稍后处理时, 例如在日志文件, 监控工具中, 或被包含到允许嵌入脚本的数据格式中时, 也适用类似注意事项.
17.5. 通过协议元素长度发起的攻击
由于 HTTP 主要使用文本型, 字符分隔的字段, 解析器经常容易受到发送很长 (或很慢) 数据流的攻击, 尤其是在实现期待某个没有预定义长度的协议元素时 (Section 2.3).
为了促进互操作性, 本规范对字段的最小大小限制给出了具体建议 (Section 5.4). 这些是最低建议, 选择它们是为了让资源有限的实现也能支持; 预计大多数实现会选择明显更高的限制.
服务器可以拒绝目标 URI 过长 (Section 15.5.15) 或请求内容过大 (Section 15.5.14) 的消息. 与容量限制相关的其他状态码已由 HTTP 扩展定义 [RFC6585].
接收方应当谨慎限制其处理其他协议元素的程度, 包括但不限于 request methods, response status phrases, field names, numeric values 和 chunk lengths. 未能限制此类处理可能因缓冲区或算术溢出而导致任意代码执行, 并增加遭受拒绝服务攻击的脆弱性.
17.6. 使用共享字典压缩的攻击
某些针对加密协议的攻击利用动态压缩产生的大小差异来揭示机密信息; 例如 [BREACH]. 这些攻击依赖于在攻击者控制的内容与机密信息之间制造冗余, 使得对两种内容使用相同字典的动态压缩算法, 在攻击者控制的内容匹配机密内容的一部分时压缩效率更高.
HTTP 消息可以通过多种方式压缩, 包括使用 TLS 压缩, 内容编码, 传输编码, 以及其他扩展或版本特定机制.
缓解此风险最有效的方法是对敏感数据禁用压缩, 或严格分离敏感数据和攻击者控制的数据, 使它们不能共享同一个压缩字典. 通过谨慎设计, 可以让一种压缩方案在有限使用场景中不被认为可利用, 例如 HPACK ([HPACK]).
17.7. 个人信息披露
客户端通常掌握大量个人信息, 包括用户为与资源交互而提供的信息 (例如用户姓名, 位置, 邮件地址, 密码, 加密密钥等), 以及用户随时间产生的浏览活动信息 (例如历史记录, 书签等). 实现需要防止个人信息意外泄漏.
17.8. 服务器日志信息的隐私
服务器能够随时间保存关于用户请求的个人数据, 这些数据可能识别用户的阅读模式或兴趣主题. 尤其是中间方收集的日志信息, 往往包含用户代理跨大量站点交互的历史, 并可追溯到个人用户.
HTTP 日志信息本质上具有机密性; 其处理通常受法律和法规约束. 日志信息需要安全存储, 分析时需要遵循适当指南. 对单个条目中的个人信息进行匿名化会有所帮助, 但通常不足以防止真实日志轨迹基于与其他访问特征的相关性而被重新识别. 因此, 即便键是伪匿名的, 以特定客户端为键的访问轨迹也不适合发布.
为了尽量降低被盗或意外发布的风险, 一旦不再需要这些信息来支持安全, 可审计性或欺诈控制等运营需求, 就应当从日志信息中清除个人可识别信息, 包括用户标识符, IP 地址和用户提供的查询参数.
17.9. URI 中敏感信息的披露
URI 旨在被共享, 而不是被保护, 即便它们标识安全资源也是如此. URI 经常显示在屏幕上, 在页面打印时添加到模板中, 并存储在各种不受保护的书签列表中. 许多服务器, 代理和用户代理会在可能被第三方看到的位置记录或显示目标 URI. 因此, 在 URI 中包含敏感, 个人可识别或高风险信息是不明智的.
当应用使用客户端侧机制, 根据用户提供的信息构造目标 URI 时, 例如使用 GET 的表单查询字段, 可能会提供不适合包含在 URI 中的潜在敏感数据. 在这些情况下, 通常更倾向于使用 POST, 因为它通常不会构造 URI; 相反, 表单的 POST 会在请求内容中传输潜在敏感数据. 不过, 这会妨碍缓存, 并且对本来是安全请求的操作使用了不安全方法. 替代规避办法包括在构造 URI 之前转换用户提供的数据, 或过滤数据, 只包含常见且不敏感的值. 同样, 将查询结果重定向到另一个 (服务器生成的) URI 可以从后续链接中移除潜在敏感数据, 并为后续复用提供可缓存响应.
由于 Referer 头字段会告诉目标站点导致该请求的上下文, 它可能泄露用户的即时浏览历史, 以及引用资源 URI 中可能存在的任何个人信息. Section 10.1.3 描述了对 Referer 头字段的限制, 以处理其部分安全注意事项.
17.10. 应用对字段名的处理
服务器经常使用非 HTTP 网关接口和框架来处理收到的请求并为响应生成内容. 出于历史原因, 此类接口常常将收到的字段名作为外部变量名传递, 使用适合环境变量的名称映射.
例如, [RFC3875] 的 Section 4.1.18 中 Common Gateway Interface (CGI) 定义的协议特定元变量适用于收到的头字段中那些不对应 CGI 标准变量的字段; 该映射包括在每个名称前加上 "HTTP_", 并将所有连字符 ("-") 实例改为下划线 ("_"). 许多其他应用框架继承了同一映射, 以便简化应用从一个平台迁移到另一个平台.
在 CGI 中, 收到的 Content-Length 字段会作为元变量 "CONTENT_LENGTH" 传递, 其字符串值与收到的字段值匹配. 相比之下, 收到的 "Content_Length" 头字段会作为协议特定元变量 "HTTP_CONTENT_LENGTH" 传递, 如果应用错误地读取协议特定元变量而非默认变量, 可能导致混淆. (这种历史实践就是 Section 16.3.2.1 不鼓励创建包含下划线的新字段名的原因.)
遗憾的是, 如果字段名到不同接口名称的映射不完整或有歧义, 可能导致安全漏洞. 例如, 如果攻击者发送名为 "Transfer_Encoding" 的字段, 朴素接口可能会将其映射到与 "Transfer-Encoding" 字段相同的变量名, 从而产生潜在的 request smuggling 漏洞 ([HTTP/1.1] 的 Section 11.2).
为缓解相关风险, 建议执行此类映射的实现使映射对名称中可能收到的全部 octet 范围都无歧义且完整 (包括 HTTP 语法不鼓励或禁止的 octet). 例如, 含有异常名称字符的字段可能导致请求被阻止, 特定字段被移除, 或该名称以不同前缀传递以区别于其他字段.
17.11. 重定向后片段的披露
虽然 URI 引用中使用的片段标识符不会在请求中发送, 但实现者应当意识到它们会对用户代理以及因响应而运行的任何扩展或脚本可见. 尤其是当发生重定向, 且原始请求的片段标识符被 Location 中的新引用继承时 (Section 10.2.2), 这可能产生将一个站点的片段披露给另一个站点的效果. 如果第一个站点在片段中使用个人信息, 它应当确保重定向到其他站点时包含一个 (可能为空的) fragment 组成部分, 以阻止这种继承.
17.12. 产品信息披露
User-Agent (Section 10.1.5), Via (Section 7.6.3) 和 Server (Section 10.2.4) 头字段经常泄露相应发送方软件系统的信息. 理论上, 这会让攻击者更容易利用已知安全漏洞; 实践中, 攻击者往往会尝试所有潜在漏洞, 而不管表面上使用的软件版本是什么.
作为网络防火墙网关的代理, 应当对可能识别防火墙后主机的头部信息传输采取特殊预防措施. Via 头字段允许中间方用伪名替换敏感机器名称.
17.13. 浏览器指纹识别
浏览器指纹识别是一组技术, 通过用户代理随时间保持的独特特征集合来识别特定用户代理. 这些特征可能包括与其使用底层传输协议的方式, 功能能力和脚本环境相关的信息, 但这里特别关注的是可能通过 HTTP 传达的一组独特特征. 指纹识别被视为隐私问题, 因为它能够随时间跟踪用户代理行为 ([Bujlow]), 而用户对其他形式的数据收集 (例如 cookie) 可能拥有的相应控制在这里并不存在. 许多通用用户代理 (即 Web 浏览器) 已采取措施降低其指纹.
有若干请求头字段可能向服务器泄露足够独特的信息, 从而支持指纹识别. From 头字段最明显, 但预期 From 只会在用户希望自我标识时发送. 同样, Cookie 头字段被有意设计为支持重新识别, 因此指纹识别问题只适用于 cookie 被禁用或受配置限制的情况.
User-Agent 头字段可能包含足以唯一识别特定设备的信息, 通常是在与其他特征结合时, 尤其是用户代理发送了关于用户系统或扩展的过多细节时. 不过, 最不符合大多数用户预期的独特信息来源是主动协商 (Section 12.1), 包括 Accept, Accept-Charset, Accept-Encoding 和 Accept-Language 头字段.
除指纹识别问题外, 对 Accept-Language 头字段的详细使用可能泄露用户认为具有隐私性质的信息. 例如, 理解给定语言集合可能与某个特定民族群体成员身份强相关. 限制此类隐私损失的一种方法是, 用户代理除非对站点明确授予许可, 否则省略发送 Accept-Language; 这种许可可以在检测到表明语言协商可能有用的 Vary 头字段后通过交互获得.
在使用代理增强隐私的环境中, 用户代理在发送主动协商头字段时应当保守. 提供高度头字段可配置性的通用用户代理, 应当告知用户如果提供过多细节可能导致隐私损失. 作为极端隐私措施, 代理可以过滤中继请求中的主动协商头字段.
17.14. 验证器保留
本规范定义的验证器并不旨在确保表示的有效性, 防范恶意更改, 或检测路径上攻击. 最多, 当所有参与方行为良好时, 它们可以支持更高效的缓存更新和乐观并发写入. 最糟情况下, 条件会失败, 客户端收到的响应也不会比没有条件请求的 HTTP 交换更有害.
entity-tag 可能以产生隐私风险的方式被滥用. 例如, 站点可能故意构造一个语义上无效但对用户或用户代理唯一的 entity-tag, 在具有较长新鲜度时间的可缓存响应中发送它, 然后在后续条件请求中读取该 entity-tag, 作为重新识别该用户或用户代理的手段. 只要用户代理保留原始缓存条目, 这样的识别标签就会成为持久标识符. 缓存表示的用户代理应当确保在用户执行维护隐私的操作时清除或替换缓存, 例如清除已存储的 cookie 或切换到隐私浏览模式.
17.15. 使用 Range 的拒绝服务攻击
不受约束的多范围请求容易受到拒绝服务攻击, 因为请求同一数据的许多重叠范围所需的工作量, 与尝试以许多部分服务所请求数据所消耗的时间, 内存和带宽相比非常小. 服务器应当忽略, 合并或拒绝过分的范围请求, 例如请求两个以上重叠范围, 或在单个集合中请求许多小范围, 特别是当这些范围无明显理由地乱序请求时. Multipart range requests 并非设计用于支持随机访问.
17.16. 认证注意事项
HTTP 认证主题的一切都属于安全注意事项, 因此下面的注意事项列表并不详尽. 此外, 它仅限于一般认证框架的安全注意事项, 而不是讨论具体认证方案的所有潜在注意事项 (这些内容应当记录在定义相应方案的规范中). 各类组织维护着关于 Web 应用安全的专题信息以及当前研究链接 (例如 [OWASP]), 包括实践中实现和使用认证方案时的常见陷阱.
17.16.1. 凭据的机密性
HTTP 认证框架没有定义单一机制来维护凭据的机密性; 相反, 每个认证方案都会定义凭据在传输前如何编码. 虽然这为未来认证方案的发展提供了灵活性, 但不足以保护那些本身不提供机密性或不能充分防范重放攻击的现有方案. 此外, 如果服务器期望每个单独用户都有特定凭据, 即便凭据内容保持机密, 这些凭据的交换也会产生识别该用户的效果.
HTTP 依赖底层传输级或会话级连接的安全属性来提供字段的机密传输. 依赖单个用户认证的服务, 在交换凭据之前需要受保护连接 (Section 4.2.2).
17.16.2. 凭据和空闲客户端
现有 HTTP 客户端和用户代理通常会无限期保留认证信息. HTTP 不提供让源服务器指示客户端丢弃这些缓存凭据的机制, 因为协议不了解用户代理如何获取或管理凭据. 使凭据过期或撤销凭据的机制可以作为认证方案定义的一部分来规定.
凭据缓存可能干扰应用安全模型的情况包括但不限于:
-
客户端机器在用户离开后保持空闲且无人看管, 此后服务器可能希望让客户端再次提示用户输入凭据.
-
应用包含会话终止指示 (例如页面上的 "logout" 或 "commit" 按钮), 此后应用的服务器端 "知道" 客户端没有进一步保留凭据的理由.
鼓励缓存凭据的用户代理提供一个易于访问且受用户控制的机制, 用于丢弃缓存凭据.
17.16.3. 保护空间
仅依赖 "realm" 机制建立保护空间的认证方案, 会把凭据暴露给源服务器上的所有资源. 已经成功向某个资源发出认证请求的客户端, 可以对同一源服务器上的其他资源使用相同认证凭据. 这使得不同资源有可能收集其他资源的认证凭据.
当源服务器在同一 origin 下托管多个参与方的资源时 (Section 11.5), 这尤其值得关注. 可能的缓解策略包括限制对认证凭据的直接访问 (即不让 Authorization 请求头字段的内容可用), 以及为每个参与方使用不同主机名 (或端口号) 来分离保护空间.
17.16.4. 附加响应字段
向通过未加密信道发送的响应中添加信息, 可能影响安全和隐私. 仅 Authentication-Info 和 Proxy-Authentication-Info 头字段的存在, 就表明正在使用 HTTP 认证. 认证方案特定参数的内容可能暴露附加信息; 这需要在这些方案的定义中加以考虑.