9. 安全考虑
本节旨在告知开发者, 信息提供者和用户: 与 HTTP 语义及其通过 Internet 传输信息的用途相关的已知安全问题. 与消息语法, 解析和路由相关的考虑事项见 [RFC7230], 与 HTTP 缓存相关的考虑事项见 [RFC7234].
下面的考虑事项列表并不穷尽. 与 HTTP 语义相关的大多数安全问题, 涉及保护服务器端应用程序 (HTTP 接口背后的代码), 保护用户代理对通过 HTTP 接收内容的处理, 或安全使用从 HTTP header fields 获得的信息. 许多这类问题是相互依赖的; 客户端软件中的弱点可被用于利用服务器软件中的漏洞, 反之亦然.
9.1. 基于文件名和路径名的攻击
源服务器经常使用其本地文件系统来管理从 target URI 到资源表示的映射. 大多数文件系统并非为防范恶意文件名或路径名而设计. 因此, 当源服务器将目标资源映射到文件, 文件夹或目录时, 需要避免访问对系统具有特殊意义的名称.
例如, UNIX, Microsoft Windows 和其他操作系统使用 ".." 作为路径组成部分, 表示当前目录的上一级目录, 并使用特殊命名的路径或文件名向系统设备发送数据. 其他类型的存储系统中也可能存在类似的命名约定. 同样, 本地存储系统在处理无效或意外字符时, 往往令人烦恼地偏向用户友好而非安全, 以可能导致非预期模式的方式重新组合这些字符.
实现需要注意不要对同一字符串执行多次 escape 或 unescape, 因为对先前已转义的字符串执行 unescape 可能产生不安全字符. 尤其是, 在没有额外检查的情况下, 简单地对 request-target 执行 unescape 并将其用作文件系统路径是不安全的.
注意, 本规范对 target URI 的限制不足以防止这类攻击; 还必须辅以特定于实现的检查.
9.2. 基于命令, 代码或查询注入的攻击
源服务器经常使用 URI 内的参数来标识系统服务, 选择数据库条目或选择数据源. 然而, 不能信任请求中接收的数据. 攻击者可以构造任意请求数据元素 (method, request-target, header fields 或 body), 使其包含在传递给命令调用, 语言解释器或数据库接口时可能被误解为命令, 代码或查询的数据.
例如, SQL 注入是一种常见攻击, 攻击者会在 request-target 或 header fields 的某些部分插入额外的查询语言 (例如 Host, Referer 等). 如果接收到的数据被直接用于 SQL SELECT 语句, 查询语言可能会被解释为数据库命令, 而不是简单的字符串值. 尽管这种实现漏洞很容易预防, 但它极其常见.
一般而言, 资源实现应避免在组装 shell 命令或查询时使用请求数据. 当这种使用不可避免时, 需要在使用前对数据进行适当转义 (以接收该数据的系统所要求的方式为准).
9.3. 个人信息泄露
客户端通常掌握大量个人信息, 包括用户为与资源交互而提供的信息 (例如用户姓名, 位置, 邮件地址, 密码, 加密密钥等), 以及用户一段时间内的浏览活动信息 (例如历史记录, 书签等). 实现需要防止此类信息的非预期泄露.
9.3.1. 通过应用数据泄露
应用程序应将其信息披露限制在完成请求所必需的范围内, 并避免披露特定于用户或应用程序内部结构的信息 (Section 5.5.3 and Section 7.4.2).
9.3.2. 通过 Referer 泄露
Referer header field 允许客户端向服务器宣告客户端从何处获得 request-target, 这可能揭示有关用户上下文或浏览历史的信息. 在 request-target 由第三方来源提供的情况下, 用户可能希望对该信息保密 (例如来自医疗信息的链接). 因此, 用户代理应向用户提供不发送 Referer 字段的选项, 或发送泄露较少信息的字段版本 (例如仅 origin) (Section 5.5.2).
如果引用页面是通过安全协议接收的, 客户端不应在 (非安全的) HTTP 请求中包含 Referer header field.
使用 HTTP 协议的服务作者不应使用带有表单编码内容的 GET 和 POST 请求来传输敏感信息, 例如个人身份信息, 账号, 密码等, 因为这会导致这些数据在未加密状态下通过 request-target 或内容传输. 服务设计者应使用带有 message bodies 的 POST 方法来传输这类敏感信息, 并注意不要将此类信息包含在 request-target 中, 因为它们可能暴露在日志, 书签等位置.
9.3.3. 通过 User-Agent 泄露
User-Agent header field 通常包含足以唯一标识某个特定设备的信息, 尤其是在与其他特征组合时, 如果用户代理发送了过多关于用户系统或扩展的信息则更是如此. 实现应限制此类信息 (Section 5.5.3).
9.4. 服务器日志信息的隐私
服务器能够长期保存关于用户请求的个人数据, 这些数据可能标识用户的阅读模式或感兴趣的主题. 特别是, 在 intermediary 处收集的日志信息通常包含用户代理跨多个站点交互的历史, 并可追踪到单个用户.
HTTP 日志信息本质上属于机密信息; 其处理通常受到法律和法规约束. 日志信息需要安全存储, 并在分析时遵循适当准则. 对单个条目中的个人信息进行匿名化会有所帮助, 但通常不足以防止真实日志轨迹基于与其他访问特征的关联而被重新识别. 因此, 绑定到特定客户端的访问轨迹应被匿名化, 或被视为机密信息.
为最大限度降低被盗或意外发布的风险, 应尽快清除日志信息.
9.5. 重定向后的片段泄露
虽然 URI references 中使用的 fragment identifiers 不会在请求中发送, 但实现者应意识到, 它们会对用户代理以及因响应而运行的任何扩展或脚本可见. 特别是, 当发生重定向且原始请求的 fragment identifier 被 Location 中的新引用继承时 (Section 7.1.2), 这可能产生安全后果.
9.6. 产品信息泄露
Server 和 User-Agent header fields 通常会泄露相应发送方软件系统的信息. 理论上, 这会使攻击者更容易利用已知安全漏洞; 实际上, 无论表面上正在使用的软件版本如何, 攻击者往往都会尝试所有潜在漏洞.
作为穿越网络防火墙的门户的代理, 应对可能标识防火墙后主机的 header 信息传输采取特别预防措施.Via header field 允许 intermediaries 使用假名替换敏感机器名称.
9.7. 浏览器指纹识别
浏览器指纹识别是一组技术, 用于通过用户代理独有的一组特征在一段时间内标识某个特定用户代理. 这些特征可能包括与其如何使用底层传输协议, 功能能力和脚本环境相关的信息, 但这里特别关注的是可能经由 HTTP 传达的一组独有特征. 指纹识别被视为隐私问题, 因为它能在一段时间内跟踪用户代理的行为 (Section 9.4), 却没有用户对其他形式数据 (如 cookies) 可能拥有的相应控制.
有许多 request header fields 可能向服务器泄露足够独特, 能够启用指纹识别的信息.From header field 最明显, 尽管预期 From 只会在用户希望进行自我标识时发送. 同样, Cookie header fields 是有意设计为支持重新识别的, 因此指纹识别方面的担忧只在用户代理禁用或限制 cookies 时适用.
User-Agent header field 可能包含足以唯一标识特定设备的信息, 通常是在与其他特征组合时, 尤其是在用户代理发送过多关于用户系统或扩展的细节时. 然而, 用户最不预期会成为独特信息来源的是主动协商 (Section 3.4.1), 包括 Accept, Accept-Charset, Accept-Encoding 和 Accept-Language header fields.
除指纹识别问题外, 对 Accept-Language header field 的详细使用还可能泄露用户认为具有私密性质的信息. 例如, 理解某一组给定语言可能与某个特定族群的成员身份高度相关. 限制这种隐私损失的一种方式是, 用户代理除白名单站点外省略发送 Accept-Language, 也许可在检测到表明语言协商可能有用的 Vary header field 后, 通过交互将站点加入白名单.
在使用代理来增强隐私的环境中, 用户代理在发送主动协商 header fields 时应保持保守. 提供高度 header field 可配置性的通用用户代理, 应告知用户: 如果提供过多细节, 可能导致隐私损失. 作为极端隐私措施, 代理可以过滤中继请求中的主动协商 header fields.
9.8. 验证器保留
响应元数据 (Section 7.2) 中包含的 validators 应仅由缓存保留到正常处理和缓存响应过期所需的时间. 长时间保留 validators 可能导致隐私问题, 因为旧 validators 可能被用于关联单个用户跨多个请求的活动, 即使服务器没有显式地将 validator 值与单个用户关联. 不作为缓存运行的用户代理不应长时间保留 validators.