• 为什么要引入SSH?

  • SSH 连接机制

    • SSH特性

    • 认识不同的Key

    • SSH连接过程

  • SSH1和SSH2特点及区别

    • SSH两种认证方式的特点

  • SSH协议的实现

    • ssh命令用法

    • sshd Server命令使用

    • Ssh_client配置解析

  • SSH抓包分析

SSH 工作原理

SSH 全称(Secure Shell),是一项创建在应用层和传输层基础上的安全协议,为计算机上的Shell(壳层)提供安全的传输和使用环境。

相对telnet来讲,ssh主要被发明用来替代telnet,完善了其安全性问题。Secure Shell(缩写为SSH),由IETF的网络工作小组(Network Working Group)所制定。

传统的网络服务程序,如rshFTPPOPTelnet其本质上都是不安全的;因为它们在网络上用明文传送数据、用户帐号和用户口令,很容易受到中间人(man-in-the-middle)攻击方式的攻击。就是存在另一个人或者一台机器冒充真正的服务器接收用户传给服务器的数据,然后再冒充用户把数据传给真正的服务器。

SSH是目前较可靠,专为远程登录会话和其他网络服务提供安全性的协议。利用SSH协议可以有效防止远程管理过程中的信息泄露问题。通过SSH可以对所有传输的数据进行加密,也能够防止DNS欺骗和IP欺骗。

SSH之另一项优点为其传输的数据可以是经过压缩的,所以可以加快传输的速度。SSH有很多功能,它既可以代替Telnet,又可以为FTP、POP、甚至为PPP提供一个安全的“通道”。

SSH是一种协议,监听在TCP的22号端口,主要提供安全的远程登录功能。

平时大家经常所讲的SSH,其实是OpenSSH.OpenSSHSSH协议的开源实现,基于SSH协议实现的工具中OpenSSH最为出名。在嵌入式服务器中。用户通过远程主机通过OpenSSH连接服务器。在Linux下基于tty运行login程序供client程序连接。

如果是在本地的话通过VGA外接显示器和键盘即可完成服务器的管理工作,但我们不可能一直在服务器身边,想想机房多冷,机房环境也不适合人长期居住。所以不有了远程连接服务器的需求。需要有这样的一种协议需要能与服务器连接、通信、并且能和服务器通信的,基于这样的协议上有这样的工具来实现该功能。而且二者要通过C/S的架构来相互通信。这意味着服务器要随时监听在一个端口上供client来连接。

为什么要引入SSH?

一言以蔽之,就是因为网络的不安全性!

传统的网络通信方式,如telnetrloginFTPhttp 都是以明文方式传送用户名和密码进行身份验证的,这是十分危险的。在共享网络环境下,只要用一些嗅探工具(如大名顶顶的sniffer portable 和wireshark)就很容易捕获到登录者的用户名和密码,进而控制远程的主机,而合法用户却毫无察觉。

早期计算机通信是通过telnet进行,telnet是应用层基于明文传输的协议,因为telnet(teletype network)的出生可以追溯到ARPANET公司早期UNIX系统早期所需。因当时计算机的应用者非常少且爱众很窄,所以TELNET的设计毫无安全性可言,完全是基于性能和可用性考虑。在现代计算机的发展来看,好鸟多于坏鸟的时候,宇宙黑暗丛林中裸奔,TELNET是淘汰品,多数系统默认是关闭telnet服务。telnet监听23/tcp端口。telnet的取代品是SSH

SSH最初是UNIX系统上的一个程序,后来又迅速扩展到其他操作平台。SSH在正确使用时可弥补网络中的漏洞。SSH客户端适用于多种平台。几乎所有UNIX平台—包括HP-UX、Linux、AIX、Solaris、Digital UNIX、Irix,以及其他平台—都可运行SSH

ssh当下有2个版本,分别是SSHV1 SSHV2,主流V2版本,v1版本仍存在中间人攻击安全风险。

SSH 连接机制

SSH对于大多数同学都不陌生,目前主流的云服务提供上也是通过SSH来提供链接的安全保障,比如AWS通过使用下载的私钥(private key)实现与EC2实例安全连接、GitHub通过上传的公钥(public key)实现基于git协议(底层使用SSH)远程库管理。

很多童鞋希望了解这些方式的背后,SSH是如何工作的:

  • SSH如何保证客户端与服务端通行的安全
  • SSH采用什么加密协议
  • SSH是通过对称加密还是非对称加密数据在传输过程的安全
  • SSH如何保证数据完整性
  • SSH的密码认证方式和密钥认证方式分别如何实现,有何差异
  • ......

本次内容我们只对SSH的流程进行简单说明,其中会描述在SSH流程中是如何通过加密等技术解决安全和数据一致性问题,希望对解答某些童鞋的疑问和更进一步了解SSH有所帮助。

SSH从安全和性能两方面综合考虑,结合使用了Public KeySecret Key

  • Public Key:非对称加密,安全,但效率低,不适合大规模进行数据的加密和解密操作
  • Secret Key:对称机密,高效,但安全性相对较低,Key的分发尤其不方便

Public KeySecret Key涉及密码学和加密算法,我们后面会专栏介绍

SSH特性

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

  • 加密

避免数据内容泄漏

  • 通信的完整性

避免数据被篡改,以及发送或接受地址伪装(检查数据是否被篡改,数据是否来自发送者而非攻击者) SSH-2通过MD5SHA-1实现该功能,SSH-1使用CRC-32

  • 认证

识别数据发送者和接收者身份,客户端验证SSH服务端的身份:防止攻击者仿冒SSH服务端身份,避免中介人攻击和重定向请求的攻击;OpenSSH通过在know-hosts中存储主机名和host key对服务端身份进行认证 服务端验证请求者身份:提供安全性较弱的用户密码方式,和安全性更强的per-user public-key signatures;此外SSH还支持与第三方安全服务系统的集成,如Kerberos

  • 授权

用户访问控制

  • Forwarding or tunneling to encrypt other TCP/IP-based sessions

可以通过SSH为Telnet、FTP等提供通信安全保障,支持三种类型的Forwarding操作:1> Port Forwarding;2> X Forwarding;3> Agent Forwarding

本文只涉及加密、通信完整性、认证三个方面内容。

认识不同的Key

SSH结合使用了Public KeySecret Key.

Public Key用于在建立安全通道前在客户端和服务端之间传输Secret Key和进行身份认证;重要

Secret Key则用来作为SSH会话的安全保证,对数据进行加密和解密。

名称生命周期创建类型描述
Host Key持久化服务端Public Key对服务端进行认证
User Key持久化用户Public Key对客户端(用户)进行认证
Server Key默认为1小时服务端Public Key用于对Session Key进行加密(仅SSH-1协议有,SSH-2对其进行了增强,这里Server Key作为一个概念便于在流程中进行描述)
Session Key客户端会话(Session)Secret Key用于对传输的数据进行加密

SSH连接过程

SSH处理过程可以分解成几个主要阶段:

  • 协议协商阶段
  • 服务端认证阶段
  • 客户端认证阶段
  • 数据传输阶段

每个阶段均涉及到客户端与服务端的多次交互,通过这些交互过程完成包括证书传输、算法协商、通道加密等过程。

协议协商阶段

  • 服务端打开服务端口(默认为22),等待客户端连接
  • 客户端发起TCP连接请求,服务端接收到该请求后,向客户端发送包括SSH协议版本信息
  • 客户端接根据该版本信息与自己的版本,决定将要使用的SSH版本,并向服务端发送选用的SSH版本信息
  • 服务端检查是否支持客户端的决定使用的SSH版本

至此,双方完成协议协商。如果该过程中,客户端或服务端发送SSH版本无法兼容,任何一方都可以断开连接。

服务端认证阶段

完成协议协商阶段后,客户端与服务端已经建立明文的通信通道,之后进入服务端认证阶段。

SSH协议中没有明确的服务端认证过程,而通过一系列的服务端与客户端的交互来确定服务端的身份,该过程还会完成Host Key、User Key、Session Key等在客户端与服务端之间的传输。

  • 建立连接后,服务端向客户端发送:
  1. Host Key:用于认证服务端的身份
  2. Server Key:用于帮助建立安全的数据传输通道
  3. 8字节的随机数:客户端通过在下一次响应中包含该随机数,防止IP地址欺诈
  4. 服务端支持的加密算法、压缩方式和认证方式

这个时候,客户端和服务端使用Host Key、Server Key和8字节的随机数生成一个128位的MD5值,作为此次会话的session id

  1. 客户端在接收到服务端Host Key后,会检查自己的knows host数据库中(一般为~/.ssh/know_hosts文件),是否已经包含当前服务端的Host Key,如果有则继续下一步;如果没有或包含当前服务端的其他Host Key则,有用户决定是否信任该服务端,或终止当前连接。
  2. 客户端向服务端发送session Key

出于性能考虑,SSH采用对称加密(Secret Key),对实际通信内容进行加密,即Session Key。因此Session Key的安全尤为重要,一旦Session Key泄漏给攻击者,那所有的通信数据都可能被攻击者截获。

由于当前通道还是采用明文方式,客户端采用Host KeyServer KeySession Key进行两次加密来加强安全性。

服务端得到Session Key后,客户端和服务端就可以通过Session Key对数据进行加密解密操作,

到此,双方完成安全(加密)通道的建立。

Host KeyServer Key都是Public Key(非对称加密),只有通过服务端的私钥(Private Key)才能对其解密,以得到Session Key。在正式使用安全通道前,客户端要求服务端发送使用Session Key加密的确认信息,以验证服务端的身份。为避免Session Key的泄漏,SSH还采取了其他安全措施,Session Key仅保存在内存避免其泄漏;周期性更换Server Key,默认为1小时(SSH 2Server Key安全进一步增强)。

客户端认证阶段

SSH提供多种客户端认证方式。

SSH-1:

  • Password
  • Public Key
  • Kerberos
  • Rhosts && RhostsRSA
  • TIS

SSH-2:

  • Password
  • Public Key
  • hostbased 在SSH-2中考虑Rhosts存在安全漏洞,废弃了这种方式。

这里之讨论我们经常使用的的PasswordPublic Key方式。此时安全通道已经及建立,之后的所有内容都通过Session Key加密后进行传输。

Password

Password方式即客户端提供用户和密码,服务端对用户和密码进行匹配,完成认证。类Unix系统中,如OpenSSH的框架,一般通过系统的本地接口完成认证。

Password的优势是简单,无需任何而外的配置就可以使用。缺点密码不便于记忆,过于简单的密码容易被暴力破解。

Public Key

Public Key认证的基本原理是基于非对称加密方式,分别在服务端对一段数据通过公钥进行加密,如果客户端能够证明其可以使用私钥对这段数据进行解密,则可以说明客户端的身份。因为服务端需要使用客户端生成的密钥对的公钥对数据首先加密,所以需要先将公钥存储到服务端的密钥库(Auhtorized Key)。还记得Github中使用git协议push代码前需要先添加SSH KEY吗?

下面详细介绍一个通过Public Key进行客户端认证的过程:

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

SSH1和SSH2特点及区别

SSH协议主要存在两个版本SSH1SSH2,而且这两个版本是不兼容的,这就是说,使用SSH1协议的客户端是不能登录SSH2协议的服务器。

SSH1又分为1.3和1.5两个版本。SSH1采用DES、3DES、BlowfishRC4等对称加密算法保护数据安全传输,而对称加密算法的密钥是通过非对称加密算法(RSA)来完成交换的。SSH1使用循环冗余校验码(CRC)来保证数据的完整性,但是后来发现这种方法有缺陷。

SSH2避免了RSA的专利问题,并修补了CRC的缺陷。SSH2用数字签名算法(DSA)和Diffie-Hellman(DH)算法代替RSA来完成对称密钥的交换,用消息证实代码(HMAC)来代替CRC。同时SSH2增加了AESTwofish等对称加密算法。

SSH两种认证方式的特点

从客户端来看,SSH提供两种级别的安全验证。

  • 第一种级别(基于口令的安全验证)

只要你知道自己帐号和口令,就可以登录到远程主机。所有传输的数据都会被加密,但是不能保证你正在连接的服务器就是你想连接的服务器。可能会有别的服务器在冒充真正的服务器, 也就是受到“中间人”这种方式的攻击。

例子: 如何以中间人攻击的方式攻击SSH1 简单地说,SSH1的通信过程是这样的:                服务器                             客户

握手阶段                                  SYN                       <---------------------------                               SYN ACK                       --------------------------->                                  ACK                       <---------------------------

协议协商阶段                               版本信息                       --------------------------->                               版本信息                       <--------------------------- 交换密钥阶段                            明码传输的服务器公钥                       --------------------------->                           服务器公钥加密的会话密钥                       <--------------------------- 认证阶段                                确认信息                       <---------------------------                           会话密钥加密的用户名                       <---------------------------                                应答信息                       --------------------------->                           会话密钥加密的口令信息                       <---------------------------                                应答信息                       ---------------------------> 数据通信阶段                       ............................

这个过程中,由于监听者处于中间人的地位,它可以在交换密钥的阶段从截获的数据流中取出服务器的公钥,保存起来,然后用自己生成的一对密钥中的公钥替换数据包中的公钥,发送给客户。这样,当客户生成会话密钥的时候就会用我们的公钥加密。当我们收到客户发送的会话密钥的时候,可以用我们所掌握的私钥解密,得到会话密钥,然后再用保存下来的服务器公钥加密,发送给服务器。此时,服务器、客户和监听者都有了同一个会话密钥,以后的通信对于监听者来说就如同明文了。

  • 第二种级别(基于密匙的安全验证)

需要依靠密匙,也就是你必须为自己创建一对密匙,并把公用密匙放在需要访问的服务器上。如果你要连接到SSH服务器上,客户端软件就会向服务器发出请求,请求用你的密匙进行安全验证。服务器收到请求之后, 先在该服务器上你的主目录下寻找你的公用密匙,然后把它和你发送过来的公用密匙进行比较。如果两个密匙一致, 服务器就用公用密匙加密“质询”(challenge)并把它发送给客户端软件。客户端软件收到“质询”之后就可以用你的私人密匙解密再把它发送给服务器.

用这种方式,你必须知道自己密匙的口令。但是,与第一种级别相比,第二种级别不需要在网络上传送口令.

第二种级别不仅加密所有传送的数据,而且“中间人”这种攻击方式也是不可能的(因为他没有你的私人密匙)。但是整个登录的过程可能需要10秒。

SSH协议的实现

Opensshssh协议的开源实现,Linux各发行版上的默认实现。

  • Sshd:ssh daemon 服务端  /etc/ssh/sshd_config

  • Ssh: ssh client 客户端 /etc/ssh/ssh_config (ssh — OpenSSH SSH client (remote login program)

  • sftp

  • scp

  • 查看ssh有哪些包

[%12%root@DS128 ~]# rpm -qa | grep -i ssh
libssh2-1.4.3-10.el7.x86_64
openssh-clients-6.6.1p1-22.el7.x86_64
ksshaskpass-0.5.3-7.el7.x86_64
openssh-6.6.1p1-22.el7.x86_64
openssh-server-6.6.1p1-22.el7.x86_64
sshpass-1.05-5.el7.x86_64
  • 查看openssh-client安装了哪些包
[%13%root@DS128 ~]# rpm -ql openssh-clients
/etc/ssh/ssh_config
/usr/bin/scp
/usr/bin/sftp
/usr/bin/slogin
/usr/bin/ssh
/usr/bin/ssh-add
/usr/bin/ssh-agent
/usr/bin/ssh-copy-id
/usr/bin/ssh-keyscan
/usr/lib64/fipscheck/ssh.hmac
/usr/libexec/openssh/ssh-pkcs11-helper
/usr/share/man/man1/scp.1.gz
/usr/share/man/man1/sftp.1.gz
/usr/share/man/man1/slogin.1.gz
/usr/share/man/man1/ssh-add.1.gz
/usr/share/man/man1/ssh-agent.1.gz
/usr/share/man/man1/ssh-copy-id.1.gz
/usr/share/man/man1/ssh-keyscan.1.gz
/usr/share/man/man1/ssh.1.gz
/usr/share/man/man5/ssh_config.5.gz
/usr/share/man/man8/ssh-pkcs11-helper.8.gz

ssh命令用法

  • ssh:基于ssh协议完成远程连接
ssh [USERNAME@]HOST [COMMAND]
ssh [-l USERNAME]  HOST [COMMAND]

常用选项:

  • -l user:以指定的用户登录远程主机;省略用户名使用本地用户名作为远程登录的用户名;

  • -p port:指明远程服务器的端口;

  • -X:支持X11转发;

  • -Y:支持信任的X11转发;

  • X:x-window协议

  • X11转发:在本地显示远程主机上的图形窗口;本地是X图形界面,或者提供了x service;

  • -o StrictHostKeyChecking=no:自动接收保存认证密钥,不用手动输入yes确认;可在/etc/ssh/ssh_config配置

  • scp:基于ssh协议完成远程跨主机复制

scp  [options]  SRC...  DEST/
scp  [options]  SRC  DEST
PULL:  scp  [options]  [user@]host:/PATH/TO/SOMEFILE   /PATH/TO/SOMEFILE
PUSH:    scp  [options]  /PATH/TO/SOMEFILE   [user@]host:/PATH/TO/SOMEFILE

常用选项:

  • -r:递归复制,复制目录;

  • -p:保持原文件的权限信息;

  • -q:静默模式;

  • -P PORT:指明远程主机ssh协议监听的端口;

  • sftp命令

(1)ftp:file transfer protocol,文件传输协议,明文;

安全的文件传输机制:

ftps: ftp over ssl
sftp: ftp over ssh

(2)sftp:基于ssh协议文件传输,C/S架构

服务端:由sshd服务进程管理,是sshd的一个子系统,在centos系统上的openssh上,默认为启动状态;/usr/libexec/openssh/sftp-server 客户端:即sftp;

连接至远程主机:

sftp  user@host
sftp> help

sshd Server命令使用

  • 常用选项
-1      Forces ssh to try protocol version 1 only.  使用ssh1版本
-2      Forces ssh to try protocol version 2 only.  使用ssh2版本
-4      Forces ssh to use IPv4 addresses only.  连接ipv4
-6      Forces ssh to use IPv6 addresses only.  连接ipv6
-l login_name  # 指定登录端口
-p port  #  指定远程服务器ssh服务的连接端口
-o option # 定义连接本身的工作模式   # 放在配置文件中的选项,放在命令行以覆盖配置文件中的配置(StrictHostKeyChecking,User,。。。非常多)
-X: 支持X11转发,图形协议的转发,支持图形程序。如firefox.(ssh连接远程服务器,借用本地的X11服务支持远程服务器对图形化的支持)
-Y: 只支持信息的X11转发
-b bind_address  本地有多块网卡时,绑定自己本地的哪块网卡作为源地址对外
-i identity_file  指定本地的密钥文件。如果不指定默认~/.ssh/id_dsa, ~/.ssh/id_ecdsa,~/.ssh/id_ed25519 and ~/.ssh/id_rsa.如果文件名变更,则需要指定了

Ssh_client配置解析

该配置用法配置较为独特,因为互联网的主机非常多,每台主机的系统不一样可能导致的配置连接也需不同,那我们有可能需要针对不同的主机做不同的配置。

# Host www.master.com   # 可以单独指定某台主机
#   ForwardAgent no
#   ForwardX11 no


#
 Host *.master.com  # 可以某些配置
#   ForwardAgent no
#   ForwardX11 no


#
 Host *  泛匹配
#   ForwardAgent no
#   ForwardX11 no

SSH抓包分析

  • 抓包观察ssh协议流程:

SSH 工作原理_javassh

由上图可知ssh协议主要经历握手->协商->密钥交换->加密数据传输这么几个阶段

SSH 工作原理_java_02sftpSSH 工作原理_java_03telnet

由上图清晰可见用户名和密码

  • Http明文传输验证实验

SSH 工作原理_java_04http

由上图可见 cisco路由器的名字叫R1 enable密码是123