跳到内容

传输层安全性备忘录

简介

本备忘录提供关于为使用传输层安全性 (TLS) 的应用程序实施传输层保护的指导。它主要关注如何使用 TLS 保护通过 HTTPS 连接到 Web 应用程序的客户端,尽管其中大部分指导也适用于 TLS 的其他用途。正确实施后,TLS 可以提供多项安全优势:

  • 机密性:提供保护,防止攻击者读取流量内容。
  • 完整性:提供保护,防止流量修改,例如攻击者重放针对服务器的请求。
  • 认证:使客户端能够确认它们已连接到合法服务器。请注意,除非使用客户端证书,否则客户端的身份不会被验证。

SSL 与 TLS

安全套接字层 (SSL) 是最初用于为 HTTP 流量提供加密的协议,以 HTTPS 的形式存在。SSL 有两个公开发布的版本——版本 2 和版本 3。这两个版本都存在严重的加密弱点,不应再使用。

出于各种原因,该协议的下一个版本(实际上是 SSL 3.1)被命名为传输层安全性 (TLS) 版本 1.0。随后,TLS 版本 1.1、1.2 和 1.3 已发布。

“SSL”、“SSL/TLS”和“TLS”等术语经常互换使用,在许多情况下,当指代更现代的 TLS 协议时会使用“SSL”。本备忘录将使用“TLS”一词,除非指代旧协议。

服务器配置

仅支持强协议

通用 Web 应用程序应默认使用 TLS 1.3(必要时支持 TLS 1.2),并禁用所有其他协议。

在特定且不常见的情况下,如果 Web 服务器需要适应依赖过时且不安全浏览器(如 Internet Explorer 10)的旧客户端,激活 TLS 1.0 可能是唯一的选择。然而,由于安全隐患,应谨慎采用此方法,并且通常不建议。此外,应启用 "TLS_FALLBACK_SCSV" 扩展,以防止对新客户端的降级攻击。

请注意,PCI DSS 禁止使用 TLS 1.0 等旧协议

仅支持强密码套件

TLS 支持大量不同的密码套件(或密码族),它们提供不同级别的安全性。在可能的情况下,只应启用 GCM 密码套件。但是,如果需要支持旧版客户端,则可能需要其他密码套件。至少,应始终禁用以下类型的密码套件:

  • 空密码
  • 匿名密码
  • EXPORT 密码

Mozilla 基金会为 Web、数据库和邮件服务器提供了一个易于使用的安全配置生成器。此工具允许站点管理员选择他们正在使用的软件,并接收一个优化以平衡各种浏览器版本和服务器软件的安全性和兼容性的配置文件。

设置合适的 Diffie-Hellman 群

早于 TLS 1.3 协议版本的 Diffie-Hellman 参数生成实践,用于临时 Diffie-Hellman 密钥交换(由密码套件名称中的“DHE”或“EDH”字符串表示),存在实际问题。例如,客户端在服务器参数的选择上没有发言权,这意味着它只能无条件接受或放弃,并且随机参数生成常常导致拒绝服务攻击(CVE-2022-40735, CVE-2002-20001)。

TLS 1.3 通过 `supported_groups` 扩展将 Diffie-Hellman 群参数限制为已知群。可用的 Diffie-Hellman 群有 `ffdhe2048`、`ffdhe3072`、`ffdhe4096`、`ffdhe6144`、`ffdhe8192`,如 RFC7919 中规定。

默认情况下,openssl 3.0 启用所有上述群。要修改它们,请确保 `openssl.cnf` 中存在正确的 Diffie-Hellman 群参数。例如:

openssl_conf = openssl_init
[openssl_init]
ssl_conf = ssl_module
[ssl_module]
system_default = tls_system_default
[tls_system_default]
Groups = x25519:prime256v1:x448:ffdhe2048:ffdhe3072

Apache 配置如下:

SSLOpenSSLConfCmd Groups x25519:secp256r1:ffdhe3072

NGINX 上相同的群配置如下:

ssl_ecdh_curve x25519:secp256r1:ffdhe3072;

对于 TLS 1.2 或更早版本,建议不要设置 Diffie-Hellman 参数。

禁用压缩

应禁用 TLS 压缩,以防止一种漏洞(昵称为 CRIME),该漏洞可能允许攻击者恢复敏感信息,例如会话 cookie。

修补加密库

除了 SSL 和 TLS 协议中的漏洞外,SSL 和 TLS 库中也曾出现大量历史漏洞,其中 Heartbleed 是最广为人知的。因此,确保这些库及时更新到最新的安全补丁非常重要。

测试服务器配置

服务器加固完成后,应进行配置测试。OWASP 测试指南中关于 SSL/TLS 测试的章节包含更多测试信息。

有许多在线工具可用于快速验证服务器配置,包括:

此外,还有许多离线工具可供使用:

证书

使用强密钥并保护它们

用于生成密码密钥的私钥必须足够强大,以应对私钥和相应证书的预期生命周期。目前的最佳实践是选择至少 2048 位的密钥大小。有关密钥生命周期和可比较密钥强度的更多信息可在此处 hereNIST SP 800-57 中找到。

私钥还应使用文件系统权限和其他技术和管理控制来防止未经授权的访问。

使用强加密哈希算法

证书应使用 SHA-256 作为哈希算法,而不是较旧的 MD5 和 SHA-1 算法。这些算法存在一些加密弱点,并且不被现代浏览器信任。

使用正确的域名

证书的域名(或主题)必须与呈现证书的服务器的完全限定名称匹配。历史上,这存储在证书的 `commonName` (CN) 属性中。然而,现代版本的 Chrome 忽略 CN 属性,并要求 FQDN 存在于 `subjectAlternativeName` (SAN) 属性中。为了兼容性,证书应在 CN 中包含主要 FQDN,并在 SAN 中包含 FQDN 的完整列表。

此外,创建证书时应考虑以下事项:

  • 考虑是否也应包含“www”子域。
  • 不要包含不合格的主机名。
  • 不要包含 IP 地址。
  • 不要在面向外部的证书上包含内部域名。
    • 如果服务器可以使用内部和外部 FQDN 访问,请为其配置多个证书。

谨慎考虑使用通配符证书

通配符证书可能很方便,但它们违反了最小权限原则,因为单个证书对域的所有子域(如 *.example.org)都有效。当多个系统共享通配符证书时,证书私钥被泄露的可能性会增加,因为该密钥可能存在于多个系统上。此外,此密钥的价值显着增加,使其成为对攻击者更具吸引力的目标。

围绕通配符证书使用的问题很复杂,并且网上有各种其他讨论

在评估使用通配符证书的风险时,应考虑以下方面:

  • 仅在确实需要时使用通配符证书,而不是为了方便。
    • 考虑使用 ACME,允许系统自动请求和更新自己的证书。
  • 切勿将通配符证书用于不同信任级别的系统。
    • 两个 VPN 网关可以使用共享的通配符证书。
    • Web 应用程序的多个实例可以共享一个证书。
    • VPN 网关和公共 Web 服务器不应共享通配符证书。
    • 公共 Web 服务器和内部服务器不应共享通配符证书。
  • 考虑使用执行 TLS 终止的反向代理服务器,这样通配符私钥只存在于一个系统上。
  • 应维护共享证书的所有系统列表,以便在证书过期或被泄露时可以更新它们。
  • 通过为子域(例如 `*.foo.example.org`)或单独的域颁发通配符证书来限制其范围。

为应用程序的用户群选择合适的认证机构

为了赢得用户的信任,证书必须由受信任的认证机构(CA)签名。对于面向 Internet 的应用程序,这应该是一个众所周知并被操作系统和浏览器自动信任的 CA。

LetsEncrypt CA 提供免费的域名验证 SSL 证书,所有主流浏览器都信任这些证书。因此,请考虑从 CA 购买证书是否有任何额外的好处。

对于内部应用程序,可以使用内部 CA。这意味着证书的 FQDN 将不会被暴露(无论是暴露给外部 CA,还是公开在证书透明度列表中)。然而,该证书只会被导入并信任用于签名它们的内部 CA 证书的用户信任。

使用 CAA 记录限制哪些 CA 可以颁发证书

认证机构授权(CAA)DNS 记录可用于定义哪些 CA 允许为域颁发证书。该记录包含一个 CA 列表,任何未包含在该列表中的 CA 都应拒绝为该域颁发证书。这有助于防止攻击者通过声誉较差的 CA 为域获取未经授权的证书。如果它应用于所有子域,从管理角度来看也很有用,因为它限制了管理员或开发人员可以使用的 CA,并防止他们获取未经授权的通配符证书。

考虑证书的验证类型

证书有不同的验证类型。验证是认证机构(CA)用于确保您有权拥有证书的过程。这就是授权。CA/浏览器论坛是一个由 CA 和浏览器供应商以及其他对网络安全感兴趣的各方组成的组织。他们根据验证类型设定 CA 必须遵循的规则。基本验证称为域名验证(DV)。所有公开发布的证书都必须经过域名验证。此过程涉及证书中请求的名称或端点控制的实际证明。这通常涉及 DNS 中的质询和响应,发送到官方电子邮件地址,或发送到将获得证书的端点。

组织验证(OV)证书在证书主题中包含请求者的组织信息。例如:C = GB, ST = Manchester, O = Sectigo Limited, CN = sectigo.com。获取 OV 证书的过程需要通过一种能向 CA 证明他们确实与正确公司通话的方法与请求公司进行官方联系。

扩展验证(EV)证书提供更高层次的验证,并包含所有 DV 和 OV 验证。这可以有效地被视为“此站点确实由 Example Company Inc. 运营”与“此域名确实是 example.org”之间的区别。最新的扩展验证指南

历史上,这些在浏览器中显示方式不同,通常在地址栏中显示公司名称或绿色图标或背景。然而,截至 2019 年,没有主流浏览器以这种方式显示 EV 状态,因为他们不认为 EV 证书提供任何额外的保护。(Chromium 涵盖 Chrome、Edge、Brave 和 Opera。Firefox Safari

由于所有浏览器和 TLS 栈都不知道 DV、OV 和 EV 证书之间的区别,因此它们在安全性方面实际上是相同的。攻击者只需达到对域的实际控制级别即可获得流氓证书。攻击者获取 OV 或 EV 证书所付出的额外努力丝毫不会增加事件的范围。事实上,这些行为很可能意味着被检测。获取 OV 和 EV 证书的额外麻烦可能会造成可用性风险,应考虑到这一点来审查其使用。

应用程序

所有页面都使用 TLS

所有页面都应使用 TLS,而不仅仅是那些被认为是敏感的页面,例如登录页面。如果任何页面不强制使用 TLS,这可能会给攻击者提供机会来嗅探敏感信息(例如会话令牌),或者向响应中注入恶意 JavaScript,从而对用户进行其他攻击。

对于面向公众的应用程序,Web 服务器监听未加密的 HTTP 连接(端口 80),然后立即通过永久重定向(HTTP 301)重定向它们可能是合适的,以向手动输入域名的用户提供更好的体验。此后,应使用 HTTP 严格传输安全 (HSTS) 头部来支持,以防止他们将来通过 HTTP 访问该站点。

仅限 API 的端点应完全禁用 HTTP,并且仅支持加密连接。当无法实现时,API 端点应拒绝通过未加密 HTTP 连接发出的请求,而不是重定向它们。

不要混合 TLS 和非 TLS 内容

通过 TLS 可用的页面不应包含任何通过未加密 HTTP 加载的资源(例如 JavaScript 或 CSS)文件。这些未加密的资源可能允许攻击者嗅探会话 cookie 或向页面注入恶意代码。现代浏览器也会阻止尝试将活动内容通过未加密 HTTP 加载到安全页面中。

所有 Cookie 都应标记为带有 “Secure” 属性,该属性指示浏览器仅通过加密的 HTTPS 连接发送它们,以防止它们从未加密的 HTTP 连接中被嗅探。这很重要,即使网站不监听 HTTP(端口 80)也如此,因为执行主动中间人攻击的攻击者可能会向用户呈现端口 80 上的欺骗性 Web 服务器,以窃取其 Cookie。

防止敏感数据缓存

尽管 TLS 在数据传输过程中提供了保护,但一旦数据到达请求系统,它就不再提供任何保护。因此,此信息可能会存储在用户浏览器的缓存中,或由任何配置为执行 TLS 解密的拦截代理存储。

当响应中返回敏感数据时,应使用 HTTP 头部指令浏览器和任何代理服务器不要缓存信息,以防止其被存储或返回给其他用户。这可以通过在响应中设置以下 HTTP 头部来实现:

Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0

使用 HTTP 严格传输安全

HTTP 严格传输安全 (HSTS) 指示用户的浏览器始终通过 HTTPS 请求站点,并防止用户绕过证书警告。有关实施 HSTS 的更多信息,请参阅 HTTP 严格传输安全备忘录

客户端证书和双向 TLS

在典型的 TLS 配置中,服务器上的证书允许客户端验证服务器的身份,并提供它们之间的加密连接。然而,这种方法有两个主要缺点:

  • 服务器缺乏验证客户端身份的机制。
  • 攻击者如果获得域的有效证书,则可以拦截连接。这种拦截通常被企业用于检查 TLS 流量,方法是在其客户端系统上安装受信任的 CA 证书。

作为双向 TLS (mTLS) 核心的客户端证书解决了这些问题。在 mTLS 中,客户端和服务器都使用 TLS 相互验证身份。客户端使用自己的证书向服务器证明其身份。这不仅能够对客户端进行强身份验证,而且即使中间方在客户端系统上拥有受信任的 CA 证书,也能防止其解密 TLS 流量。

挑战与考量

由于存在一些挑战,客户端证书在公共系统中很少使用:

  • 颁发和管理客户端证书涉及大量的管理开销。
  • 非技术用户可能会觉得安装客户端证书很困难。
  • 组织对 TLS 解密的实践可能会导致客户端证书认证(mTLS 的一个关键组件)失败。

尽管存在这些挑战,但对于高价值应用程序或 API,特别是当用户具有技术背景或属于同一组织时,应考虑使用客户端证书和 mTLS。

公钥绑定

公钥绑定可用于确保服务器证书不仅有效且受信任,而且与服务器预期的证书匹配。这提供了针对能够获取有效证书的攻击者的保护,无论是通过利用验证过程中的弱点,损害受信任的认证机构,还是拥有客户端的管理访问权限。

公钥绑定通过 HTTP 公钥绑定(HPKP)标准添加到浏览器中。然而,由于一些问题,它随后被弃用,并且不再被现代浏览器推荐或支持

然而,公钥绑定仍然可以为移动应用程序、厚客户端和服务器到服务器通信提供安全优势。这在绑定备忘录中进行了详细讨论。