luokuning / blogs

翻译,随笔,以及懒得整理……
81 stars 2 forks source link

理解 SSH 加密和连接过程 #8

Open luokuning opened 7 years ago

luokuning commented 7 years ago

并不逐字翻译,原文请点这里

介绍

SSH (安全 shell),是一个安全协议,同时也是安全地管理远程服务器时用的最多的方法。它提供了一种能够在客户端和服务器端建立安全传输和验证,以及执行远程命令的方法,而这里面使用了多种加密技术。

这篇文章我们会学习 SSH 使用的底层的加密技术以及其用于建立安全连接的具体方法,这些知识会对你理解不同层的加密和双方建立连接到验证所需的不同步骤有所帮助。

对称加密、非对称加密和哈希 (Hashes,散列)

为了确保信息的安全传输,SSH 在事物中的多个地方采用了多种不同类型的数据操纵技术,包括对称加密,非对称加密以及哈希。

对称加密

加密和解密数据所用的组件之间的关系可以确定当前加密方法是对成加密还是非对成加密,简单来说就是,如果一个密钥能够同时加密和解密数据,那么它就是对称加密。这也意味着任何持有这个密钥的人都能解密由这个密钥加密的数据。

对称加密通常被称为"共享密钥"或者"私有密钥"加密,典型的情况就是一个密钥负责所有的操作,或者一对密钥,但是这一对密钥的关系很简单,通常能根据其中一个轻易地推出另一个。

对成加密被 SSH 用来加密整个连接。和很多人想的不一样,非对称加密中的公/私钥匙对只是用来验证,而不是用来加密连接的。对称加密甚至能够防止密码认证阶段的数据被偷窥。

建立这个密钥需要客户端和服务器端同时工作,并且生成的密钥是不能让外部知道的。密钥通过称为密钥交换算法的过程创建,此算法可以让客户端和服务器端各自利用一些私有的数据和一些共享的公开的数据就能计算出一样的密钥,这个过程后面会详细说明。

由此过程创建的对称加密密钥是基于会话 (session-based) 的,并且服务器端和客户端实际通信就是用的这个密钥加密,所以一旦建立连接,剩下的所有数据传输都必须用这个共享密钥加密。这一步是在认证客户端之前完成的。

SSH 可以配置使用多种不同的对称加密算法,包括 AES, Blowfish, 3DES, CAST128, 和 Arcfour,双方会协商选择一种都支持的算法。

以 Ubuntu 14.04 为例,客户端和服务器默认的算法列表可能是: aes128-ctr, aes192-ctr, aes256-ctr, arcfour256, arcfour128, aes128-gcm@openssh.com, aes256-gcm@openssh.com, chacha20-poly1305@openssh.com, aes128-cbc, blowfish-cbc, cast128-cbc, aes192-cbc, aes256-cbc, arcfour。所以假设两台 Ubuntu 服务器相互连接(在没有更改默认算法列表的情况下),会使用 aes128-ctr 作为它们的加密算法。

非对称加密

非对称加密不同于对称加密,它需要两个密钥,其中一个称为私钥,另一个称为公钥

公钥可以任意共享,它与其配对的私钥相关联,但是私钥却不能从公钥推导出来。两者之间的数学关系确保了用公钥加密的数据只能由匹配的私钥才能解密出来。这是单向的,意味着公钥不能解密自己加密的数据,也不能解密私钥加密的数据。

译者注:其实并不是不能解密私钥加密的数据,作者这里的意思是不应该用私钥加密传输信息的方式来保证数据安全。因为算法上公钥和密钥是相等的,公钥加密的信息私钥可以解密,私钥加密的信息公钥也可以解密,但是公钥加密的信息公钥自己不能解密,所以考虑到公钥是共享的,不应该使用私钥来加密传输信息,而应该用来签名,这也是为什么非对称加密技术只能用来验证而不是加密整个连接。

私钥应该是完全保密的,这是公钥模式工作的关键。私钥是唯一能解密由公钥加密的数据的东西,基于这个事实,任何人能够解密加密过的数据就代表他拥有了私钥。

SSH 在几个不同的地方使用了非对称加密,在用于建立对称加密 (用于加密会话) 的初始密钥交换过程中就使用了非对称加密。这个阶段双方都生成了钥匙对,并且交换了公钥以产生将用于对称加密的共享密钥。

另一个更好的说明 SSH 怎么利用非对称加密的地方是 SSH 基于密钥的身份验证。SSH 密钥对可以用于向服务器端验证客户端,客户端首先会生成密钥对,并且把公钥上传到远程服务器,存放在 ~/.ssh 目录下的 authorized_keys 文件中。

在建立了保护通讯的对称加密之后,客户端还必须认证以允许访问服务器。服务器可以使用上面所说文件中保存的公钥来加密一个质询消息发送到客户端,如果客户端能够解密这个消息,那就证明确实拥有相匹配的私钥,这个时候服务器应该允许此客户端访问。

哈希 (Hashes)

SSH 还利用了另一种数据结构: 加密哈希。加密哈希函数是一种创建简明"签名"和对一组信息生成摘要的方法,这种方法生成的结果唯一且不可预测,也不能根据哈希结果逆向推出原始信息。

同样的数据会产生同样的哈希值,修改原始数据的任何部分都会产生完全不同的哈希值。用户虽然不能根据哈希值推出原始的信息,但是能知道给定的数据是否产生了给定的哈希值。

基于这些特性,哈希主要用来验证数据的完整性和通讯的真实性。哈希在 SSH 中的主要应用是 HMAC ,或者说是基于哈希的消息认证码,用来确保接收到的消息文本是完整未修改过的。

作为上面说的对称加密协商的一部分,双方会选择一种消息认证码 (MAC) 算法,选择的过程就是客户端会列出一系列算法,服务器端会选择自身支持的第一项。

当协商加密完成后的所有消息发送时都要包含 MAC 数据,这样接收方才能验证消息的完整性。MAC 是由对称加密中的共享密钥计算而来的,发送出去的数据包包含一系列的信息以及实际消息本身。

MAC 自身会放到对称加密信息之外,也就是利用共享密钥加密的实际数据之外,作为数据包的最后部分。安全研究人员通常推荐都是先加密数据,再计算 MAC 数据。

SSH 是如何工作的?

你可能已经基本对 SSH 的工作机制有所了解了,SSH 协议采用客户端-服务器模型来验证彼此并加密它们之间传输的数据。

服务器组件会侦听指定的端口,并负责协商安全的连接、认证连接方,并且会衍生 (spawn) 一个正确的环境给已经认证的客户端。

而客户端负责发起与服务器的 TCP 握手、协商安全连接、验证服务器的身份与之前记录的信息匹配,并且提供认证的凭证。

SSH 会话在两个独立的阶段建立,第一个阶段是协商建立加密以保护未来通讯的过程,第二个阶段就是认证阶段。

协商会话加密

当客户端发起 TCP 连接时,服务器以其支持的协议版本作为响应,如果客户端能匹配其中的某个协议,则连接继续进行。服务器需要提供自身的主机公钥,客户端就可以使用这个密钥来检查这是否是预期的主机。

这个时候双方会使用被称为 Diffie-Hellman 的算法来协商一个会话密钥,这个算法可以让客户端和服务器各自通过组合一些私有数据和彼此交换的公有数据来得到相同的私有会话密钥 (secret session key)。

会话密钥将会用来加密整个会话,用与这个过程的公钥私钥对与用于向服务器认证客户端的 SSH 钥匙对完全不同。

使用了经典的 Diffie-Hellman 算法的基本过程大概是这样:

  1. 首先双方同意使用同一个大质数,它将作为种子值 (seed value)。
  2. 双方确认同一种加密生成器 (通常为 AES),其将用于以预定义的方式处理值。
  3. 双方再各自提出一个对彼此保密的质数,这个数就是生成会话密钥阶段的私钥 (与认证阶段的 SSH 私钥是完全不同的)。
  4. 上一步中的私钥,与加密生成器和第一步中的大质数可以计算出一个公钥,这个公钥是可以共享的。
  5. 双方交换第 4 步中的公钥。
  6. 这个时候双方使用第 3 步中各自的私钥、对方的公钥以及原始的那个大质数计算出共享密钥,虽然这是由每一方独立计算的,但是算法会保证双方得到相同的密钥值。
  7. 此后的会话将使用上一步计算得到的共享密钥加密。

用于加密接下来通讯的共享密钥加密称为二进制分组协议。上面说的过程允许每一方同等的参与生成共享密钥,而不是由某一方享有控制权。要注意的是,共享密钥并不是通过不安全的信道传输的,而是通过上面说的算法各自算出来的。

生成的密钥是对称密钥,意味着它可以解密由自己加密的信息,这样的话接下来的所有通讯外界是无法破解的。

建立了会话加密之后,接下来就是用户认证阶段。

认证用户

这一阶段涉及用户认证和服务器决定是否允许客户端访问。基于服务器能够接受的程度,有多种不同的方法用于认证。

最简单的可能就是密码认证: 服务器简单地提示客户端需要输入相应的密码。密码通过已经协商好的密钥加密,因此它是安全的。

虽然密码是被加密过的,但是由于对密码复杂性的限制,通常并不推荐这种方法。与其他认证方法相比,自动脚本可以轻松破解正常长度的密码。(译者注: 这种方法很容易被中间人攻击 (Man-in-the-middle attack),推荐使用下面的方法)

最流行和被推荐的最多的方法是使用 SSH 密钥对。SSH 密钥对是非对成密钥对,意味着这两个相关的密钥提供不同的功能。

公钥加密的数据只能被私钥解密,而且公钥可以自由的共享,因为不能从公钥导出私钥。

使用 SSH 密钥对认证的过程在对称加密之后开始,大致过程可能就是:

  1. 客户端首先向服务器发送用于认证的密钥对的 ID。
  2. 服务器根据 ID 检查客户端指定登录账户目录下的 authorized_keys 文件。
  3. 如果服务器在这个文件里找到了指定 ID 对应的公钥,那么它会用这个公钥加密一串随机数。
  4. 将加密的随机数发回客户端。
  5. 如果客户端确实有对应的密钥,那么它就能够解密出原始的那串随机数。
  6. 解出随机数之后,组合第一阶段得到的会话密钥生成一个新值,并且计算这个新值的 MD5 值。
  7. 客户端发送这个 MD5 值给服务器,作为第 4 步对服务器的响应。
  8. 服务器使用自己的会话秘钥和发送给客户端的随机数计算一个 MD5 值,如果这个值和客户端返回的 MD5 值相等,那么表示此客户端确实拥有对应的私钥,验证通过。

非对称加密允许服务器使用公钥加密数据发送给客户端,客户端只要能解密数据就能证明它用于对应的私钥。SSH 的整个模型都很好的利用了两种不同类型加密 (对称加密和非对称加密) 的特定优势。

结语

了解 SSH 中通讯协商和各个层中的加密能够更好的帮助你理解当我们登录远程服务器的时候都发生了什么。希望你现在对各个组件和算法之间的关系,以及这些部分是如何组织在一起的有一个更好的了解。

DevinXian commented 7 years ago

批注的那一段挺好的,分清使用场合

kbrx93 commented 7 years ago

学习了。感谢。