CODE & ZEN

凯旋的博客

我是孙凯旋 @skx926
一名来自中国的 iOS 开发者
写过 Android
也会点 Web
深知付出更多才能收获更多
唯有在技术的道路上勤勤恳恳
方得片刻安心


SSH协议工作过程

说到SSH,我们很多人都用过,比如我们通过git提交代码到Github的时候需要先添加本机的public key到Github网站,使用SSH远程连接VPS来对服务器进行操作。但是SSH究竟是什么,它是如何工作的呢?

定义

SSH全称Secure Shell,是一个提供数据通信安全、远程登录、远程指令执行等功能的安全网络协议,由芬兰赫尔辛基大学研究员Tatu Ylönen,于1995年提出,其目的是用于替代非安全的Telnet、rsh、rexec等远程Shell协议。之后SSH发展了两个大版本SSH-1和SSH-2。

SSH协议工作过程

SSH工作过程可以分解成几个主要阶段: - 连接建立 - 协议协商 - 算法协商 - 密钥交换 - 用户认证 - 服务请求 - 数据传输和连接关闭

下面我们通过终端发起一个SSH远程登录的请求并使用Wireshark抓包情况来具体分析一下SSH连接的各个阶段:

$ ssh skx926@45.32.31.176

建立TCP连接

  1. 服务端打开22端口,等待客户端连接。
  2. 客户端向服务器发起TCP连接进行三次握手。

由上图可以看出,前面的三个包正好是TCP进行三次握手的阶段。

协议协商

在客户端和服务端建立TCP连接之后客户端和服务端互发自己支持的SSH版本信息,双方收到版本号之后会选用两者中较小的版本来进行通讯。 由上图可以看出双方都支持SSH2.0-OpenSSH_7.4

算法协商

客户端和服务端分别发送所支持的算法列表给对方并确定最终使用的算法。

从上图中我们可以看到客户端发送给服务端的算法列表中有很多算法: - 用于产生会话密钥的密钥交换算法kex_algorithms - 用于数据信息加密的加密算法encryption_algorithms_client_to_serverencryption_algorithms_server_to_client - 用于数字签名和认证的主机公钥算法server_host_key_algorithms - 用户数据完整性保护的MAC算法mac_algorithms_client_to_servermac_algorithms_server_to_client

算法协商的具体规则是这样的: > 双方依次协商每一种算法(密钥交换算法、加密算法等)。每种算法的协商过程均为:从客户端的算法列表中取出第一个算法,在服务器端的列表中查找相应的算法,如果匹配上相同的算法,则该算法协商成功;否则继续从客户端算法列表中取出下一个算法,在服务器端的算法列表中匹配,直到匹配成功。如果客户端支持的算法全部匹配失败,则该算法协商失败。 某一种算法协商成功后,继续按照上述方法协商其他的算法,直到所有算法(这里是指密钥交换算法、加密算法等)都协商成功;如果某一种算法协商失败,则客户端和服务器之间的算法协商失败,服务器断开与客户端的连接。

密钥交换

加密算法协商成功后,为了保证加解密密钥的安全性,SSH利用上一步协商好的密钥交换算法在通信双方安全动态地生成和交互数据的加解密密钥,并能够有效防止第三方窃听加解密密钥。

由上图可以看出这里选择了使用Diffie-Hellman算法作为密钥交换算法,Diffie-Hellman算法的流程是这样的: 1. 双方共同选择一个大值素数作为种子值(seed value) 2. 双方共同选择一个加密生成器(通常是AES),用于后续的数值操作 3. 双方分别各自选择一个素数,该素数的值对对方保密,用于生成本次通讯的私钥(与SSH身份认证私钥无关) 4. 双方分别用各自的私钥、共同的加密生成器、和共同的素数生成各自的公钥 5. 双方将各自的公钥共享给对方 6. 双方用各自的私钥和对方发过来的公钥生成另一个密钥。根据该算法,双方各自计算出来的两个密钥是完全一样的,即“共同的秘密” 7. 该密钥被用于本次通讯所有内容的加密

由上面的流程可以看出密钥交换的过程能够让双方平等的参与密钥生成的过程,而不是由单方掌握。这种共享密钥生成的过程是安全的,双方没有交换过任何未经加密的信息。

用户认证

如上图所示会话加密通道建立之后,后面的信息就都已经加密了,Wireshark就看不到有用的信息了。

用户认证有两种方式:密码认证和公钥认证。

密码认证

密码认证比较简单,就是客户端发送用户名和密码给服务端,服务端对用户名和密码进行匹配,完成认证。

虽然前面已经建立了加密通道,密码不会在数据传输中被窃取,但是过于简单的密码还是容易被暴力破解,所有这种传统的认证方式不够安全。

公钥认证

公钥认证是基于非对称加密的,认证的前提是要先将客户端的公钥存储到服务端的authorized_keys文件中。Github上如果要使用基于SSH的git协议的话也需要将客户端的公钥添加到Github的后台。

认证流程: 1. 客户端发起一个公钥的认证请求,并发送RSA Key的模数作为标识符。 2. 服务端检查是否存在请求帐号的公钥(Linux中存储在~/.ssh/authorized_keys文件中),以及其拥有的访问权限。如果没有则断开连接 3. 服务端使用对应的公钥对一个随机的256位的字符串进行加密,并发送给客户端 4. 客户端使用私钥对字符串进行解密,并将其结合会话id生成一个MD5值发送给服务端。 结合会话id的目的是为了避免攻击者采用重放攻击(replay attack)。 5. 服务端采用同样的方式生成MD5值与客户端返回的MD5值进行比较,完成对客户端的认证。

简单来说,服务器端用公钥加密信息,客户端用私钥解密信息以证明自己持有私钥。该过程同时使用了对称加密和非对称加密,两种方式各有自己的功用。

服务请求

SSH协议支持多种应用服务。用户成功完成认证后,SSH客户端向服务器端发起服务请求,请求服务器提供某种应用。 服务请求的过程为: 1. 客户端发送 SSH_MSG_CHANNEL_OPEN 消息,请求与服务器建立会话通道,即 session; 2. 服 务 器 端 收 到 SSH_MSG_CHANNEL_OPEN 消 息 后 , 如 果 支 持 该 通 道 类型,则回复 SSH_MSG_CHANNEL_OPEN_CONFIRMATION 消息,从而建立会话通道; 3. 会话通道建立之后,客户端可以申请在通道上进行 shell 或 subsystem 类型的会话,分别对应 SSH 和 SFTP 两种类型的服务。

数据传输和连接关闭

服务请求成功,建立会话后,服务器和客户端可以在该会话上进行数据的传输。客户端将要执行的命令加密后传给服务器,服务器接收到报文,解密后执行该命令,将执行的结果加密发送给客户端,客户端将接收到的结果解密后显示到终端上。 通信结束或用户空闲时间超时后,关闭会话,断开连接。

参考文章: 理解SSH的加密与连接过程 SSH协议工作过程 SSH原理简介

最近的文章

深入理解HTTPS

HTTP为什么不安全 HTTP协议传输的数据都是未经过加密处理的,也就是说客户端和服务端使用HTTP通信的中间环节都有可能会产生信息的泄漏。 如何让HTTP更安全 有人会说很简单,把数据加密一下不就行了。嗯,说起来很简单,但是具体怎么加密呢? 对称加密还是非对称加密? 我们现在有两种加密方式可以选择 …

于  Web 继续阅读
更早的文章

解决Storyboard中设置的颜色和代码设置的颜色不一样的问题

最近发现在Storyboard中设置的颜色和用代码设置的颜色居然不一样,当时我就震惊了! 更让人震惊的是搞了这么多年iOS开发,居然现在才发现!惭愧啊。。。 网上查了一下才知道原来Xcode里的色彩选择器默认的Color Profile是Generic RGB,如下图所示: 把它改为Device …

于  iOS开发 继续阅读
comments powered by Disqus