SSH原理和应用

SSH(Secure SHell)是为远程登陆, 远程通讯等设计的安全通讯协议, 由芬兰研究员于1995年提出,其目的是用于替代非安全的Telnet、rsh、rexec等不安全的远程Shell协议.算法

SSH提供身份认证,加密通讯,完整性校验以及身份认证等功能. 工程人员常用SSH协议登陆云服务器等远程计算机, FTP, RPC等协议也可使用SSH提供的安全信道.shell

由于版权, 加密算法等缘由目前广为使用OpenSSH提供SSH服务.数据库

使用SSH

OpenSSH分为客户端和服务端, Linux和Mac OS系统通常会自带openssh-client。ubuntu

本地计算机上须要安装客户端, 远程计算机上须要运行服务端。 SSH协议默认使用TCP22端口, 远程计算机须要确保远程计算机打开了22端口.安全

远程计算机安装服务端后可使用sudo service ssh start启动, 或者使用sudo /etc/init.d/ssh start.bash

启动成功后可使用service ssh status或者ps -e中查看ssh服务的状态.服务器

远程主机配置完毕后, 在本地主机使用ssh user@host命令能够用户user的身份登陆远程主机host, 如ssh root@mycloud.com.并发

ssh服务可使用口令验证(password)或者使用私钥验证(private-key)。ssh优先使用私钥验证, 若未配置私钥则要求用户输入口令进行验证, 该口令为远程计算机上帐户的登陆口令.ssh

客户端在要求客户输入口令以前, 会先会检查本身的knows_hosts数据库中(通常为~/.ssh/know_hosts文件)是否已经包含当前服务端的密钥指纹(ECDSA key fingerprint).ide

若包含则会继续创建链接, 不然由用户判断是否相信当前客户端. 若用户不相信则中断链接, 不然继续创建链接, 并将当前服务端加入known_hosts中。

用户在判断是否相信当前服务端时需注意, 若该服务端为真正的目标服务端, 则此后与此服务端通讯过程当中基本不会再受到中间人的威胁. 若发现错误信任了假冒的服务端, 则应尽快在known_hosts中删除它的指纹, 避免计算机在通讯时默认相信该假冒者.

配置密钥对

ssh-keygen是用于生成密钥对的工具, 使用ssh-keygen生成RSA密钥对:

$ssh-keygen -t rsa -C finley@gmail.com
Generating public/private rsa key pair.
Enter file in which to save the key (~/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in ~/.ssh/id_rsa.
Your public key has been saved in ~/.ssh/id_rsa.pub.
The key fingerprint is:

上面的提示说明私钥保存在~/.ssh/id_rsa, 公钥保存在~/.ssh/id_rsa.pub. 若是必要的话也能够为私钥设置口令.

使用man ssh-keygen能够看到该命令的帮助, 最经常使用的选项有:

  • -q: 以静默方式生成
  • -b bits: 指定位数
  • -t: 指定加密方式, 包括: dsa | ecdsa | ed25519 | rsa | rsa1
  • -N new_passphrase: 指定新的私钥密码
  • -C comment: 添加注释, 一般是用户的签名
  • [-f output_keyfile]: 保存密钥的文件, 默认为~/.ssh/id_rsa

打开~/.ssh/id_rsa.pub能够看到本身的公钥, 将公钥的内容添加到远程计算机的~/.ssh/authorized_keys中,而后重启远程计算机的sshd使新的配置生效。

为了保证安全,其它用户不能拥有修改密钥的权限,若系统检测到其它用户有密钥的写(w)权限将会拒绝使用该密钥。所以,咱们将.ssh目录权限设置为700, 目录下全部相关文件权限设置为600

在终端中再次使用ssh命令登陆时就不须要输入远程计算机的登陆口令了。

一般状况下咱们只须要一对密钥, 就像咱们可使用同一个身份证在不一样的地方证实咱们的身份同样, 只不过防伪的不是难以伪造的证件而是难以猜想的私钥.

传输文件

基于ssh传输文件是一个很是方便的功能, scp能够经过ssh通道在本地计算机和远程计算机之间传递文件.

scp会先使用ssh的认证方式创建安全连接, 而后完成文件传输, 完成传输后当即断开链接.

在本地计算机的终端中执行scp命令从远程计算机下载文件:

# format : scp user@host:remote_path local_path
$ scp ubuntu@qcloud:~/1.txt 1.txt

注意在本地终端执行, 而非使用ssh命令登陆的远程终端.

scp命令与cp命令类似,第一个参数为源地址,第二个参数为目标地址, 只不过支持远程路径.

在复制目录下的全部内容时一样须要-r参数:

# format: scp -r user@host:remote_path local_path
$ scp -r ubuntu@qcloud:~/workspace workspace

目的地址写为远程地址便可将本地文件上传到远程计算机:

# format: scp local_path user@host:remote_path
$ scp 1.txt ubuntu@qcloud:~/1.txt
# format scp -r local_path user@host:remote_path
$ scp -r workspace ubuntu@qcloud:~/workspace

使用跳板机

出于安全缘由,一般集群中只有网关机能够从外网登陆,内网中机器只能从网关机登陆。若先登陆网关机做为跳板,再从网关机上登陆目标机则很是麻烦。

咱们可使用ssh的ProxyCommand功能自动使用跳板机登陆内网:

$ ssh username@internal -o ProxyCommand='ssh username@gateway -W %h:%p'

其中,ProxyCommand是登陆跳板机的ssh指令,internal是内网中目标机的地址。ssh username@internal将在跳板机上执行,internal一般为目标机的内网ip地址。

注意,这种方式要求目标机的authorized_keys中包含本地计算机的密钥。

配置主机别名

每次ssh登陆都须要输入很长的指令是一件很麻烦的事情,咱们能够在~/.ssh/config文件中配置主机别名极大的简化登陆指令:

Host gateway # 主机别名,使用`ssh gateway`命令能够直接登陆该主机
    Protocol 2  # ssh协议版本
    HostName example.com # 主机地址,支持IP或域名
    Port 22  # ssh服务端口号
    User ubuntu # 登陆用户名
    IdentityFile ~/.ssh/id_rsa # 使用的私钥文件

Host internal # 主机别名,这是一个自动跳转示例
    Protocol 2
    HostName 192.168.1.111 # 目标机的内网ip地址,一般不使用域名
    Port 22 # 内网中目标机的ssh服务端口号
    User ubuntu # 登陆目标机的用户名
    ProxyCommand ssh gateway -W %h:%p # 登陆跳板机的ssh指令,这里使用上一条配置的别名
    IdentityFile ~/.ssh/id_rsa # 登陆跳板机的私钥文件,该密钥必须包含在跳板机的authorized_keys中

Host 10.10.0.* # 使用通配符的示例,登陆HostName符合通配符的主机均可以用该配置,如:`ssh ubuntu@10.10.0.1`
    Port 22
    User ubuntu   
    ProxyCommand ssh gateway -W %h:%p

端口转发

SSH能够经过端口转发为其它协议提供安全通讯. 端口转发中涉及四台主机:

  • 本地主机LocalHost: 运行SSH客户端的主机, 即用户操做的主机
  • 远程主机RemoteHost: 运行SSH服务端的主机
  • 源主机SrcHost: 发送请求的主机
  • 目的主机DestHost: 请求要前往的主机

本地端口转发是由ssh客户端监听本地端口, 并将发往该端口的通讯由远程主机发往目标:

ssh -L LocalPort:DestHost:DestPort user@RemoteHost

配置本地转发后:

  1. 本地SSH客户端将监听LocalPort端口
  2. 全部发往该本地端口的请求将被经过SSH信道发往远程主机RemoteHost
  3. 远程主机上的SSH服务端会将请求转发到目标主机DestHost上的DestPort端口
  4. 目标主机的响应将被RemoteHost和LocalHost依次转发, 原路返回来源主机

远程转发的过程正好与本地转发相反:

ssh -R RemotePort:DestHost:DestPort user@RemoteHost

配置远程转发后:

  1. 远程主机RemoteHost上的SSH服务端将监听RemoteHost上的RemotePort端口
  2. 全部发送到RemoteHost得RemotePort端口上的请求将经过SSH信道发往本地
  3. 本地主机上的SSH客户端将请求转发到目标主机DestHost上的DestPort端口
  4. 目标主机的响应将被LocalHost和RemoteHost依次转发, 原路返回来源主机

本地转发只能请求发往固定的目的主机和目的端口, 而动态转发则会根据请求的目的和协议决定转发到的目的主机和目的端口.

ssh -D LocalPort user@RemoteHost

ssh客户端将会监听全部发往本地LocalPort的请求, 并经过远程主机中转, 转发到请求的目的地址.

该过程与本地转发相似, 不过目的主机与目的端口是根据请求动态决定的.

安全通讯原理

在进一步介绍认证过程以前, 须要先介绍一下对称加密和非对称加密的概念.

  • 对称加密: 加密和解密的密钥相同. 如典型的移位密码: C代替A,D代替B...

    这里向后移两位就是密钥, 得知向后移两位后能够将明文加密也能够将密文解密.

  • 非对称加密: 加密密钥与解密密钥不一样. 一般加密密钥公开(公钥), 解密密钥私有(私钥), 且很难经过公钥推断私钥.

非对称加密方式下, 全部人均可以使用公钥对明文进行加密, 可是只有持有私钥的人才能够解密密文.

通常来讲, 对称加密方式的加解密速度比非对称方式更快.

如今, 咱们能够开始介绍SSH认证和安全通讯的原理了.

协议协商阶段

创建SSH安全连接的第一个阶段为协议协商阶段:

  1. 服务端监听端口等待客户端链接
  2. 客户端发起TCP链接请求, 服务端接收到该请求后,向客户端发送SSH协议版本信息.
  3. 客户端接根据该版本信息与本身的版本,决定将要使用的SSH版本,并向服务端发送选用的SSH版本信息
  4. 服务端检查是否支持客户端的决定使用的SSH版本

至此,双方完成协议协商。若是该过程当中,客户端或服务端发送SSH版本没法兼容,任何一方均可以断开链接.

此时双方创建明文信道, 均没法确认对方身份.

服务端认证阶段

随后进入服务端认证阶段:

  1. 服务端向客户端发送下列信息:
    • 服务端身份公钥(Host Key), 用于认证服务端身份
    • 服务端通讯公钥(Server Key), 用于生成通讯加密密钥
  2. 客户端根据Host Key, 查询known_hosts或交由用户判断是否信任该服务端.
    若信任则继续,不然断开链接

  3. 客户端随机生成会话密钥(Session Key), 并使用服务端通讯公钥(Server Key)加密后发给服务端

  4. 服务端用本身的私钥解密获得会话密钥(Session Key)

本阶段仍然使用明文信道, 当本阶段结束时双方都有了相同且安全的会话密钥. 此后的通讯过程当中, 双方将使用会话密钥对称加密进行安全通讯.

客户端认证阶段

随后进入客户端认证阶段, 此阶段双方已创建对称加密安全信道.

  • 口令方式: 客户端提供用户和口令,服务端进行匹配完成认证.

  • 密钥方式:

    1. 客户端发起一个Public Key认证请求
    2. 服务端检查是否存在请求账号的公钥(通常在~/.ssh/authorized_keys文件中),以及其拥有的访问权限, 若是没有则断开链接.
    3. 服务端使用客户端发送的公钥对一个随机的256位的字符串进行加密,并发送给客户端.
    4. 客户端使用私钥对字符串进行解密,并生成一个MD5值发送给服务端
    5. 服务端根据原始随机字符串生成MD5值进行匹配, 确认客户端身份

至此, 双方互相确认对方身份并创建加密信道, 能够正式进行安全通讯。

相关文章
相关标签/搜索