跳到主要内容

9. 安全考虑

为使整个安全考虑内容更易访问, 传输、认证和连接文档中的安全考虑汇总在本节.

传输协议 [SSH-TRANS] 在不安全网络上提供保密信道. 它执行服务器主机认证、密钥交换、加密和完整性保护. 它还派生唯一 session id, 该标识符可由更高层协议使用.

认证协议 [SSH-USERAUTH] 提供一组机制, 可用于向服务器认证客户端用户. 认证协议中指定的各个机制使用传输协议提供的 session id, 和/或依赖传输协议的安全性与完整性保证.

连接协议 [SSH-CONNECT] 指定一种机制, 用于在保密且已认证的传输上复用多个数据流 (channel). 它还指定了用于访问交互式 shell 的 channel、用于通过安全传输代理转发各种外部协议 (包括任意 TCP/IP 协议) 的 channel, 以及用于访问服务器主机上安全子系统的 channel.

9.1. 伪随机数生成

本协议通过在用于生成会话密钥的哈希中包含随机的会话专用数据, 将每个会话密钥绑定到会话. 必须特别注意确保所有随机数质量良好. 如果这里的随机数据, 例如 Diffie-Hellman (DH) 参数, 是伪随机的, 则伪随机数生成器应当具有密码学安全性, 即使知道所有先前输出也不容易猜出下一次输出; 此外, 还需要向伪随机数生成器加入适当熵. [RFC4086] 提供了随机数和熵来源建议. 实现者应注意熵的重要性, 以及关于正确实现伪随机数生成函数之困难的善意经验警告.

给定客户端或服务器可用的熵量有时可能低于所需量. 在这种情况下, 要么不顾熵不足而使用伪随机数生成, 要么拒绝运行协议. 后者更可取.

9.2. 控制字符过滤

向用户显示文本时, 例如错误或调试消息, 客户端软件应当用安全序列替换任何控制字符, 制表符、回车和换行除外, 以避免通过发送终端控制字符实施攻击.

9.3. 传输

9.3.1. 保密性

分析或推荐具体密码算法超出了本文档和 Secure Shell 工作组范围, 但行业已经建立并接受的算法除外. 在本文编写时, 常用密码算法包括 3DES、ARCFOUR、twofish、serpent 和 blowfish. AES 已由美国 Federal Information Processing Standards 发布为 [FIPS-197], 并且也被密码学社区接受. 与往常一样, 实现者和用户应检查当前文献, 确保产品使用的密码算法未发现近期漏洞. 实现者还应检查哪些密码算法相对更强, 并建议用户优先使用较强算法而非较弱算法. 当用户主动选择较弱算法而有更强算法可用时, 实现以礼貌且不突兀的方式通知用户会是良好做法.

"none" 密码算法用于调试, 除调试目的外不应使用. [RFC2410] 充分描述了它的密码学属性, 并会表明其使用不符合本协议意图.

这些密码算法及其他密码算法的相对优劣也可在当前文献中找到. [SCHNEIER] 和 [KAUFMAN] 可能提供相关信息. 二者都描述了某些密码算法的 CBC 工作模式及其弱点. 本质上, 由于数据包序列开头高度可预测, 该模式在理论上易受选择密文攻击. 但是, 这种攻击被认为困难且不完全可行, 尤其是在使用相对较长的块大小时.

此外, 另一种 CBC 模式攻击可通过插入包含 SSH_MSG_IGNORE 的数据包来缓解. 如果没有该技术, 某个特定攻击可能成功. 要使这种通常称为 Rogaway attack [ROGAWAY], [DAI], [BELLARE] 的攻击奏效, 攻击者需要知道下一块将被加密时使用的 Initialization Vector (IV, 初始化向量). 在 CBC 模式中, 该 IV 是前一块加密输出. 如果攻击者还无法看到该数据包, 例如它仍在 SSH 实现内部缓冲区甚至内核中, 则攻击不会奏效. 如果最后一个数据包已经发送到网络, 即攻击者可以访问它, 则攻击者可以使用该攻击.

在最佳情况下, 实现者只需在数据包已经发送到网络且没有其他等待传输的数据包时添加一个额外数据包. 实现者可能希望检查是否有任何未发送数据包等待传输; 遗憾的是, 通常不容易从内核或缓冲区获得这类信息. 如果没有未发送数据包, 则应发送一个包含 SSH_MSG_IGNORE 的数据包. 如果每当攻击者知道下一数据包应使用的 IV 时都向流中添加新数据包, 攻击者就无法猜出正确 IV, 因而攻击永远不会成功.

例如, 考虑以下情形:

      Client                                                  Server
------ ------
TCP(seq=x, len=500) ---->
contains Record 1

[500 ms passes, no ACK]

TCP(seq=x, len=1000) ---->
contains Records 1,2

ACK
  1. Nagle 算法加 TCP 重传意味着两个记录会合并成一个 TCP 段.

  2. Record 2 不在 TCP 段开头, 且永远不会在开头, 因为它会被 ACK.

  3. 但攻击仍可能发生, 因为 Record 1 已经被看到.

如该示例所示, 使用 TCP 缓冲区中存在未刷新数据这一事实来判断是否需要空数据包是不安全的, 因为执行第二次 write() 时, 缓冲区将包含尚未 ACK 的 Record 1.

另一方面, 以下情况完全安全:

      Client                                                  Server
------ ------
TCP(seq=x, len=500) ---->
contains SSH_MSG_IGNORE

TCP(seq=y, len=500) ---->
contains Data

只要第二个 SSH Record 的 IV 在 Data 数据包数据确定之后才固定, 就应执行以下操作:

         read from user
encrypt null packet
encrypt data packet

9.3.2. 数据完整性

本协议确实允许禁用 Data Integrity (数据完整性) 机制. 实现者在为调试之外的任何目的暴露此功能时都应谨慎. 每当启用 "none" MAC 时, 都应明确警告用户和管理员.

只要不使用 "none" MAC, 本协议就提供数据完整性.

由于 MAC 使用 32 位序列号, 发送 232 个数据包后可能开始泄露信息. 不过, 遵循重设密钥建议应能防止该攻击. 传输协议 [SSH-TRANS] 建议在传输一吉字节数据后重设密钥, 而最小可能数据包为 16 字节. 因此, 最晚也应在 228 个数据包后重设密钥.

9.3.3. 重放

使用 "none" 之外的 MAC 可提供完整性和认证. 此外, 传输协议提供唯一会话标识符, 它部分绑定到算法和密钥交换过程中的伪随机数据, 可由高层协议用于将数据绑定到给定会话并防止先前会话中的数据被重放. 例如, 认证协议 [SSH-USERAUTH] 使用它防止重放先前会话的签名. 因为公钥认证交换在密码学上绑定到会话, 即绑定到初始密钥交换, 它们不能在其他会话中成功重放. 注意, session id 可以公开而不损害协议安全性.

如果两个会话具有相同 session id (密钥交换哈希), 则一个会话的数据包可被重放到另一个会话. 必须强调的是, 使用现代密码学方法时, 这种情况发生的概率显然极低. 当指定更大的哈希函数输出和 DH 参数时更是如此.

使用单调递增序列号作为 MAC 输入, 或在某些情况下作为 HMAC 输入进行重放检测, 已在 [RFC2085], [RFC2246], [RFC2743], [RFC1964], [RFC2025] 和 [RFC4120] 中描述. 底层构造见 [RFC2104]. 本质上, 每个数据包中的不同序列号确保至少这个 MAC 函数输入是唯一的, 并会提供攻击者无法预测的非重复 MAC 输出. 不过, 如果会话保持活动足够久, 该序列号会回绕. 如果对等方自第一次发送该序列号的数据包以来尚未重设密钥, 该事件可能给攻击者提供机会, 使其重放一个此前记录且具有相同序列号的数据包. 如果对等方已经重设密钥, 重放会被检测到, 因为 MAC 检查会失败. 因此必须强调, 对等方必须在序列号回绕前重设密钥. 自然, 如果攻击者在对等方重设密钥前尝试重放捕获的数据包, 接收方无法验证重复数据包的 MAC, 数据包会被丢弃. MAC 失败的原因是接收方会基于数据包内容、共享秘密和预期序列号形成 MAC. 由于重放数据包不会使用该预期序列号, 即该重放数据包的序列号已被接收方经过, 计算出的 MAC 不会与数据包中收到的 MAC 匹配.

9.3.4. 中间人

本协议不假定也不提供用于分发主机公钥的基础设施或手段. 预期本协议有时会在未先验证服务器主机密钥与服务器主机名之间关联的情况下使用. 这种用法易受中间人攻击. 本节描述该问题, 并鼓励管理员和用户在发起任何会话前理解验证该关联的重要性.

需要考虑三种中间人攻击情形. 第一种是攻击者在会话发起前把设备置于客户端与服务器之间. 在这种情况下, 攻击设备试图模拟合法服务器, 并在客户端发起会话时向客户端提供自己的公钥. 如果它提供服务器公钥, 除非同时访问主机私钥, 否则无法解密或签名合法服务器与客户端之间的传输. 攻击设备还会同时向合法服务器发起会话, 伪装成客户端. 如果服务器公钥在会话发起前已经安全分发给客户端, 攻击设备提供给客户端的密钥将不匹配客户端存储的密钥. 在这种情况下, 应当警告用户所提供的主机密钥与客户端缓存的主机密钥不匹配. 如第 4.1 节所述, 用户可以自由接受新密钥并继续会话. 推荐该警告提供足够信息, 使客户端设备用户能够作出知情决定. 如果用户选择使用服务器已存储公钥继续会话, 而不是使用会话开始时提供的公钥, 则由于上述随机性, 攻击者与服务器之间的会话专用数据将不同于客户端到攻击者会话和攻击者到服务器会话之间的数据. 因此攻击者无法使该攻击奏效, 因为它没有该服务器的私钥, 无法正确签名包含服务器会话专用数据的数据包.

第二种情况类似第一种, 也发生在连接时, 但它强调了安全分发服务器公钥的必要性. 如果服务器公钥未安全分发, 客户端就无法知道自己是否正在与目标服务器通信. 攻击者可能使用社会工程技术把服务器密钥冒充给毫无戒心的用户, 随后把中间人攻击设备置于合法服务器与客户端之间. 如果允许这种情况发生, 客户端会形成客户端到攻击者的会话, 攻击者会形成攻击者到服务器的会话, 并能够监视和操纵客户端与合法服务器之间的所有流量. 鼓励服务器管理员通过某些不依赖实际主机密钥完整性的安全手段提供主机密钥指纹以供检查. 可能机制见第 4.1 节, 也可以包括安全 Web 页面、实体纸张等. 实现者应当提供关于如何在其实现中最佳完成此事的建议. 由于协议可扩展, 未来协议扩展可能提供更好的机制, 用于处理连接前必须知道服务器主机密钥的需求. 例如, 可以通过安全 DNS 查询提供主机密钥指纹, 或在密钥交换期间通过 GSS-API [RFC1964] 使用 Kerberos [RFC4120] 认证服务器.

第三种中间人情形是攻击者可能尝试在会话建立后操纵对等方之间传输中的数据包. 如第 9.3.3 节所述, 这类攻击成功的概率极低. 同第 9.3.3 节一样, 该推理假定 MAC 是安全的, 并且构造使 MAC 算法产生已知输出的输入不可行. [RFC2104] 第 6 节对此有更详细讨论. 如果 MAC 算法存在漏洞或足够弱, 攻击者可能能够指定某些输入以产生已知 MAC. 由此, 它们可能修改传输中的数据包内容. 或者, 攻击者可能通过查看捕获数据包中的 MAC 来利用算法漏洞或弱点寻找共享秘密. 在任一情况下, 攻击者都可以构造一个或多个可插入 SSH 流的数据包. 为防止这种情况, 鼓励实现者使用被普遍接受的 MAC 算法, 鼓励管理员关注当前密码学文献和讨论, 确保没有使用近期发现存在漏洞或弱点的 MAC 算法.

总之, 在没有主机与其主机密钥之间可靠绑定关联的情况下使用本协议本质上是不安全的, 并且不推荐. 不过, 在非安全关键环境中它可能是必要的, 并且仍能提供对被动攻击的保护. 在本协议之上运行的协议和应用的实现者应牢记这一可能性.

9.3.5. 拒绝服务

本协议设计为在可靠传输上使用. 如果发生传输错误或消息操纵, 连接会关闭. 发生这种情况时应重新建立连接. 这类拒绝服务攻击 (wire cutter) 几乎无法避免.

此外, 本协议易受拒绝服务攻击, 因为攻击者可以在不认证的情况下强迫服务器执行 CPU 和内存密集型的连接建立与密钥交换任务. 实现者应当提供使这种攻击更困难的功能, 例如只允许来自一组已知拥有有效用户的客户端连接.

9.3.6. 隐蔽信道

协议并非设计用于消除隐蔽信道. 例如, 填充、SSH_MSG_IGNORE 消息以及协议中的若干其他位置都可以用于传递隐蔽信息, 接收方没有可靠方法验证是否正在发送此类信息.

9.3.7. 前向保密

需要注意, Diffie-Hellman 密钥交换可以提供 Perfect Forward Secrecy (PFS, 完美前向保密). PFS 基本上定义为密钥建立协议的一种密码学属性: 在给定会话之后, 会话密钥或长期私钥的泄露不会导致任何早先会话泄露 [ANSI-T1.523-2001]. 使用 [SSH-TRANS] 的 Diffie-Hellman Key Exchange 一节所述 diffie-hellman 方法, 包括 "diffie-hellman-group1-sha1" 和 "diffie-hellman-group14-sha1", 产生的 SSH 会话即使之后私有密钥/认证材料泄露也是安全的, 但如果会话密钥泄露则不安全. 因此, 按照该 PFS 定义, SSH 具有 PFS. 但是, 该属性不会传递给把 SSH 用作传输的任何应用或协议. SSH 传输层为密码认证以及其他依赖秘密数据的方法提供保密性.

当然, 如果客户端和服务器的 DH 私有参数泄露, 会话密钥也会泄露, 但这些项目可以在密钥交换完成后丢弃. 值得指出的是, 不应允许这些项目进入交换空间, 并且应在密钥交换完成后立即从内存中擦除.

9.3.8. 密钥交换方法排序

如 [SSH-TRANS] 的 Algorithm Negotiation 一节所述, 每个设备都会发送一个首选密钥交换方法列表. 最首选的方法是列表中的第一项. 推荐按密码学强度对算法排序, 最强者在前. [RFC3766] 给出了这方面的一些额外指导.

9.3.9. 流量分析

被动监视任何协议都可能让攻击者获得关于会话、用户或协议特定信息的某些内容, 而攻击者本来无法获得这些内容. 例如, 已经证明对 SSH 会话进行流量分析可以产生关于密码长度的信息 [Openwall], [USENIX]. 实现者应使用 SSH_MSG_IGNORE 数据包, 并包含随机长度填充, 以阻止流量分析尝试. 也可以发现并实现其他方法.

9.4. 认证协议

该协议的目的是执行客户端用户认证. 它假定运行在安全传输层协议之上, 该传输层协议已经认证服务器机器、建立加密通信信道, 并为本会话计算唯一会话标识符.

允许使用具有不同安全特征的多种认证方法. 服务器愿意为每个用户接受哪些方法或方法组合, 由服务器本地策略决定. 认证强度不会强于所允许的最弱组合.

服务器可以在反复认证失败后进入休眠期, 以增加攻击者进行密钥搜索的难度. 应注意避免使其成为自我拒绝服务向量.

9.4.1. 弱传输

如果传输层不提供保密性, 则应禁用依赖秘密数据的认证方法. 如果传输层不提供强完整性保护, 则应禁用更改认证数据的请求, 例如密码更改, 以防止攻击者在不被注意的情况下修改密文, 或使新的认证数据不可用, 即拒绝服务.

上文假定认证协议只在已预先认证服务器的安全传输上运行, 这一点非常重要. 部署 SSH 的人员需注意, 如果客户端没有非常强的、预先存在的服务器与该服务器主机密钥之间关联, 中间人攻击会造成后果. 具体到认证协议, 客户端可能会与中间人攻击设备形成会话, 并泄露用户名和密码等用户凭证. 即使在不泄露用户凭证的认证情况下, 攻击者仍可能以类似 honeypot 的方式捕获击键, 从而获得不应获得的信息.

9.4.2. 调试消息

设计调试消息时应特别谨慎. 如果设计不当, 这些消息可能泄露大量关于主机的信息. 如果需要高安全性, 可以在用户认证阶段禁用调试消息. 主机管理员应尽一切努力对所有事件通知消息进行分区, 并防止未经授权观察. 开发者应意识到某些正常事件和调试消息的敏感性质, 并可能需要向管理员提供指导, 说明如何防止未授权人员获得这些信息. 开发者应根据本地策略考虑尽量减少用户在认证阶段可获得的敏感信息量. 因此, 推荐在部署时默认禁用调试消息, 并要求管理员作出主动决定后才能启用. 还推荐在执行启用调试消息动作时向系统管理员显示一条表达此关切的消息.

9.4.3. 本地安全策略

实现者必须确保所提供凭证验证了所声称的用户, 并且还必须确保服务器本地策略允许该用户请求的访问. 特别是, 由于 SSH 连接协议的灵活性, 在认证时刻可能无法确定应适用的本地安全策略, 如果有的话, 因为所请求的服务类型当时尚不明确. 例如, 本地策略可能允许用户访问服务器上的文件, 但不允许启动交互式 shell. 然而, 在认证协议期间, 尚不知道用户将访问文件、尝试使用交互式 shell, 还是两者都会做. 无论如何, 如果服务器主机存在本地安全策略, 则必须正确应用和执行.

鼓励实现者提供默认本地策略, 并向管理员和用户说明其参数. 按实现者自行决定, 该默认策略可以接近无限制, 即不对用户施加限制; 也可以极其严格, 需要管理员主动更改初始默认参数以满足需求. 或者, 它也可以试图提供某种实用且立即可用的策略, 让系统管理员无需投入太多精力即可让 SSH 工作. 无论选择哪种, 都必须按上文要求应用和执行.

9.4.4. 公钥认证

使用公钥认证假定客户端主机未被攻陷. 它还假定服务器主机私钥未被攻陷.

该风险可以通过为私钥使用 passphrase 来缓解; 但是, 这不是可强制执行的策略. 建议使用智能卡或其他技术, 使 passphrase 成为可强制执行的策略.

服务器可以同时要求密码认证和公钥认证; 但这要求客户端向服务器暴露其密码. 参见下文 Password Authentication 一节.

9.4.5. 密码认证

认证协议中指定的密码机制假定服务器未被攻陷. 如果服务器已被攻陷, 使用密码认证会向攻击者泄露有效的用户名/密码组合, 这可能导致进一步攻陷.

该漏洞可以通过使用替代认证形式来缓解. 例如, 公钥认证不对服务器安全性作假定.

9.4.6. 基于主机的认证

基于主机的认证假定客户端未被攻陷. 除了将基于主机的认证与另一种认证方法组合使用外, 没有缓解策略.

9.5. 连接协议

9.5.1. 端点安全

连接协议假定端点安全. 如果服务器已被攻陷, 则该主机上访问的任何终端会话、端口转发或系统都会被攻陷. 没有缓解因素.

如果客户端已被攻陷, 且服务器未能在认证协议处阻止攻击者, 则所有暴露服务, 无论作为子系统还是通过转发暴露, 都将易受攻击. 实现者应当提供机制, 供管理员控制暴露哪些服务, 以限制其他服务的脆弱性. 这些控制可以包括控制端口转发操作可指向哪些机器和端口、哪些用户允许使用交互式 shell 设施, 或哪些用户允许使用暴露的子系统.

9.5.2. 代理转发

SSH 连接协议允许代理转发其他协议, 例如 SMTP、POP3 和 HTTP. 这可能会让希望控制位于其物理位置之外的用户访问某些应用的网络管理员感到担忧. 本质上, 转发这些协议可能违反站点专用安全策略, 因为它们可能以不可检测方式通过防火墙隧道传输. 实现者应当提供管理机制来控制代理转发功能, 以便维护站点专用安全策略.

此外, 还提供反向代理转发功能, 这同样可用于绕过防火墙控制.

如上所述, 代理转发操作期间假定端点安全. 端点安全失败会危及通过代理转发传递的所有数据.

9.5.3. X11 转发

SSH 连接协议提供的另一种代理转发形式是 X11 协议转发. 如果端点安全已被攻陷, X11 转发可能允许对 X11 服务器的攻击. 用户和管理员通常应使用适当的 X11 安全机制, 防止未经授权使用 X11 服务器. 希望进一步研究 X11 安全机制的实现者、管理员和用户可阅读 [SCHEIFLER], 并分析此前报告的 SSH 转发与 X11 交互问题, 包括 CERT 漏洞 VU#363181 和 VU#118892 [CERT].

SSH 的 X11 display forwarding 本身不足以修正 X11 安全的已知问题 [VENEMA]. 但是, SSH 或其他安全协议中的 X11 display forwarding, 结合只接受通过本地 IPC 机制连接且由权限或 Access Control List (ACL, 访问控制列表) 授权的真实 display 和 pseudo-display, 能修正许多 X11 安全问题, 只要不使用 "none" MAC. 推荐 X11 display 实现默认只允许 display 通过本地 IPC 打开. 推荐支持 X11 转发的 SSH 服务器实现默认只允许 display 通过本地 IPC 打开. 在单用户系统上, 默认允许本地 display 通过 TCP/IP 打开可能是合理的.

X11 转发协议的实现者应当实现 [SSH-CONNECT] 中描述的 magic cookie 访问检查欺骗机制, 作为防止未经授权使用代理的额外机制.