Hummus

Hummus

SSH 协议详解

SSH 概述#

SSH 是一种协议#

  • Secure Shell(安全外壳协议,简称 SSH)是一种加密的网络传输协议
  • SSH 通过在网络中创建安全隧道来实现 SSH客户端服务器之间的_连接_。
  • SSH 最常见的用途是远程登录系统,人们通常利用 SSH 来传输命令行界面和远程执行命令。

OpenSSH 开放源代码版本#

OpenSSH 是安全 Shell (SSH) 工具的开放源代码版本,Linux 及其他非 Windows 系统的管理员使用此类工具跨平台管理远程系统。

常见的 SSH 工具#

名称描述支持平台推荐
PuTTY(Free Windows)免费开源的 SSH 终端工具Windows⭐⭐⭐
WinSCPSCP 协议的文件传输工具Windows⭐⭐⭐⭐⭐
FileZilla多协议文件传输工具Windows
Linux
MacOS
⭐⭐⭐⭐
MobaXterm免费开源的 SSH 终端工具Windows⭐⭐⭐⭐
Termius全平台 SSH 终端工具Windows
Linux
MacOS
Android
IOS
⭐⭐⭐⭐⭐

SSH 协议工作原理#

SSH 协议框架中的三个子协议#

  • 传输层协议 SSH-TRANS

    提供服务器验证、完整性和保密性功能,建立在传统的 TCP/IP 协议之上。

  • 验证协议 SSH-USERAUT

    向服务器验证客户端用户,有基于用户名密码公钥两种验证方式,建立在传输层协议 SSH-TRANS 之上。

  • 连接协议 SSH-CONNECT

    将加密隧道复用为若干逻辑信道。它建立在验证协议之上。

image

SSH 工作流#

image

通过 Wireshark 抓 包分析各个阶段#

TCP 三次握手#

image

SSH 服务器端在 22 端口侦听客户端的连接请求,接收到客户端的连接建立请求后,与客户端进行三次握手,建立起一条 TCP 连接,后续的所有报文交互都在这个 TCP 连接之上进行。

版本协商#

image

服务器和客户端都会向对端发送自己支持的版本号。服务器端和客户端收到对端发送过来的版本后,与本端的版本号进行比较,双方都支持的最高版本号即为协商出的版本号。

算法协商#

image

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

algorithms包含了所有需要协商的算法

NO.描述解释
1kex_algorithms密钥交换算法 Key Exchange,里边包含了 D-H 算法,用于生成会话密钥
2server_host_key_algorithms服务器主机密钥算法 Host Key,用于生成密钥对
3encryption_algorithms_client_to_server对称加密算法,常用的有aes128-cbc,3des-cbc
4mac_algorithms_client_to_serverMac 算法,主要用于保证数据完整性
5compression_algorithms_client_to_server压缩算法

密钥交换#

image

客户端生成一个临时密钥 ephemera- public key 发送给服务器端 **【??】**

image

服务端与客户端使用 Diffie-Hellman 算法生成会话密钥 Session key。

在这个包中,服务器端将主机密钥 Host Key、会话密钥 Session key、签名等一同发送给客户端。

image

客户端回复一个 New Key,接下来进入加密通信。

image

接下来的会话过程全程加密,从抓包中已经看不到任何铭文信息了。

用户认证#

  1. 客户端向服务器端发送认证请求报文,其中携带的认证方式为 “none”。
  2. 服务器收到 none 方式认证请求,回复认证挑战报文,其中携带服务器支持、且需要该用户完成的认证方式列表。
  3. 客户端从服务器发送给自己的认证方式列表中选择某种认证方式,向服务器发起认证请求,认证请求中包含用户名、认证方法、与该认证方法相关的内容:
    • 密码认证方式中,内容为用户的密码;
    • 公钥认证方式中,内容为用户本地密钥对的公钥部分(公钥验证阶段)或者数字签名(数字签名验证阶段)。
  4. 服务器接收到客户端的认证请求,验证客户端的认证信息:
    • 密码认证方式:服务器将客户端发送的用户名和密码信息,与设备上或者远程认证服务器上保存的用户名和密码进行比较,从而判断认证成功或失败。
    • 公钥认证方式:服务器对公钥进行合法性检查,如果不合法,则认证失败;否则,服务器利用数字签名对客户端进行认证,从而判断认证成功或失败。
  5. 服务器根据本端上该用户的配置,以及用户认证的完成情况,决定是否需要客户端继续认证,分为以下几种情况:
    • 如果该种认证方式认证成功,且该用户不需要继续完成其他认证,则服务器回复认证成功消息,认证过程顺利完成。
    • 如果该种认证方式认证成功,但该用户还需要继续完成其他认证,则回复认证失败消息,继续向客户端发出认证挑战,在报文中携带服务器需要客户端继续完成的认证方式列表;
    • 如果该种认证方式认证失败,用户的认证次数尚未到达认证次数的最大值,服务器继续向客户端发送认证挑战;
    • 如果该种认证方式认证失败,且用户的认证次数达到认证次数的最大值,用户认证失败,服务器断开和客户端之间的连接。

服务请求#

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 加密通道上的数据加解密使用对称密钥算法,目前主要支持的算法有 DES、3DES、AES 等,这些算法都可以有效地防止交互数据被窃听,而且由于采用了初始化向量保护,可以防止类似于密码流复用等密码分析工具的攻击。

密钥交换算法#

对称密钥算法要求解密密钥和加密密钥完全一致,才能顺利从密文中解密得到明文。因此,要建立加密通道,必须先在通信双方部署一致的加解密密钥。部署加解密密钥的方式有多种:手工配置和第三方机构分配等。手工配置的方式扩展性差,只适合一些小型的本地网络;使用第三方机构分配密钥的方式,需要额外的第三方服务器,而且密钥在网络中传输容易被窃听。

SSH 协议使用一种安全的方式在通信双方部署密钥:密钥交换算法。利用密钥交换算法可以在通信双方动态地产生密钥,这个密钥只能被通信的双方获得,任何第三者都无法窃听,这就在源头上保证了加解密使用密钥的安全性,很好地解决了密钥分发问题。

密钥交换算法的基本原理#

  1. 客户端随机选择一个私钥 Xc(1<Xc<p1)X_c(1<X_c<p-1),计算出 Yc=gXcmodpY_c=g^{X_c} \mod p,将计算出的 YcY_c 发送给服务器端。其中,pp 是一个很大的素数,ggpp 的素根。ppgg 是双方共有的一对参数,协议允许双方通过协商获得相同的 ppgg 参数。
  2. 服务器也随机生成一个私钥 Xs(1<Xs<p1)X_s(1<X_s<p-1),计算出 YsgXsmodpY_s=g^{X_s} \mod p,也将计算出的 YsY_s 发送给客户端。
  3. 服务器接收到客户端发送过来的,按照下面的公式计算出密钥: KYcXsmodpK={Y_c}^{X_s} \mod p
  4. 客户端收到服务器端发送过来的 Y_sY\_s,同样按照下面的公式计算出密钥: KYsXcmodpK={Y_s}^{X_c} \mod p

通过上面的方法,客户端和服务器端就可以获得相同的密钥。

由上面的分析可以看出,密钥交换算法的安全性建立在计算离散对数的难度之上。算式中,由 X 计算 Y 是很容易的,但是要由 Y 计算 X 是非常困难的。在密钥交换算法中对外公开的只有 ppggYcY_cYsY_s,私钥XcX_cXsX_s是保密的,其他用户即便获取了 ppggYcY_cYsY_s也很难推断出私钥XcX_cXsX_s,从而保证了密钥的安全性。

密钥交换算法具有如下优势:

  • 扩展性更好,不需要网络管理员的多余配置;
  • 交换得到的密钥是保存在内存中,不易被读取和篡改;
  • 每个连接都会动态生成一次新的密钥,安全性更高。

用户认证机制#

基于密码的安全验证#

使用自动生成的公钥 - 私钥对来简单地加密网络连接,随后使用密码认证进行登录。具体过程如下:

  • 客户端发送登录请求,ssh user@hostname
  • 服务器接受请求,将服务器的公钥 server_rsa.pub 发送给客户端
  • 客户端输入密码,密码使用 server_rsa.pub 加密后发送给服务器(敏感信息安全传输)
  • 服务器接受加密后的密码,使用服务器私钥 server_rsa 解密,匹配认证密码是否合法

至此,身份认证通过,然后是交换会话密钥(对称加密)

  • 客户端生成会话数据加密 session_key, 使用 server_rsa.pub 加密后传输给服务器(会话密钥)
  • 服务器获取到后使用 server_rsa 解密,得到 session_key

使用会话密钥对之后传递的数据进行加密。注:使用对称加密效率高。

  • 客户端和服务器通过 session_key 进行会话数据安全传输

但是,这种认证方式无法避免中间人攻击,可能会有别的服务器在冒充真正的服务器。

公钥身份认证#

客户端生成一对公钥和私钥,并将自己的公钥复制到服务器上。客户端请求登录的时候,服务器会随机生成一个字符串并用客户端的公钥进行加密,客户端收到之后用自己的私钥解密后,再发送给服务器。服务器收到后进行比对,如果比对成功,就证明用户是可信的,直接允许登录,不再要求密码。从而避免了中间人攻击。具体过程如下:

image

基于密钥的安全验证简单的描述如图中所示。但在实际传输过程中所有的数据都是需要加密以保证数据传输安全,即同样会生成会话密钥,使用会话密钥对传输数据进行加密的过程。详细过程如下:

  • 客户端发送登录请求,ssh user@hostname
  • 服务器接受请求,将服务器的公钥发送给客户端
  • 服务器生成会话 ID (session id),设为 pp,发送给客户端。
  • 客户端生成会话密钥 (session key),设为 qq,并计算 r=p xor qr=p\ xor\ q
  • 客户端将 rrAsAs 进行加密,结果发送给服务器
  • 服务器用服务器私钥进行解密,获得 rr
  • 服务器进行 r xor pr\ xor\ p 的运算,获得 qq

至此,服务器和客户端都知道了会话密钥 qq,以后的传输数据都将被 qq 加密。

  • 客户端使用客户端私钥解密 SxS_x 得到 xx
  • 客户端计算 q+xq+x 的 md5 值 n(q+x)n(q+x)qq 为上一步得到的会话密钥
  • 客户端将 n(q+x)n(q+x) 发送给服务器
  • 服务器计算 q+xq+x 的 md5 值 m(q+x)m(q+x)
  • 服务器比较 m(g+x)m(g+x)n(g+x)n(g+x),两者相同则认证成功

至此,服务器和客户端认证通过,可以使用会话密钥进行加密和解密传输

  • 客户端和服务器通过 qq 进行会话数据安全传输

SSH 密钥#

SSH 密钥是 SSH 协议中使用的访问凭据,类似于密码。SSH 密钥授予用户自动远程访问企业的核心设备的权限。

主机密钥 Host Key#

每个主机(即计算机)都有唯一的主机密钥。

  • 在 Linux 中存储在/etc/sshssh_host_<rsa/dsa/ecdsa/ed25519>_key
  • 在 Windows 中存储在C:\ProgramData\ssh

当你首次通过 SSH 连接一台远程主机时,通常会得到这样的提示:

$ ssh user@ip-address
The authenticity of host 'ip-address (ip-address)' can't be established.
ECDSA key fingerprint is SHA256:hjn60Ix3hjduyfhjHLJKOdJSDDX6beXpfp0ypeqTOPQ+f0tU.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

当你输入yes并按下 Enter 继续之后,你就会看到这样提示:

Warning: Permanently added 'ip-address' (ECDSA) to the list of known hosts.
user@ip-address's password:

它就会以这样的形式添加到已知主机密钥列表

ip-address ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEvRRBRoCJSuJuEaXK3i3k/4Cd+uriN5cKPGbbl/Q5f5DhjduyfhjHLQXDZPVDw0reLJKmIcGcZh2qQHX5qjMLQ=

已知主机密钥列表: SSH 客户端用来存储曾经连接到的主机的主机密钥

  • 在 Linux 中存储在/etc/ssh/known\_hosts.ssh/known\_hosts
  • 在 Windows 中存储在C:\Users\User\.ssh\known_host

授权密钥 Authorized Key#

SSH 中的授权密钥是用于授予用户登录访问权限的公钥。身份验证机制称为公钥身份验证。在 OpenSSH 中可以使用ssh-keygen工具生成,通常会生成一对密钥(私钥 - 公钥),如下图所示。

image

用于服务器端的 authorized_keys 文件#

在 authorized_keys 文件为每个用户单独配置授权密钥。

  • 在 Linux 中存储在~/.ssh/authorized_keys
  • 在 Windows 中存储在C:\Users\user\.ssh\authorized_keys

你可以在 SSH 服务器的配置文件中修改它的保存路径

授权密钥内容如下所示:

ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBN+Mh3U/3We4VYtV1QmWUFIzFLTUeegl1Ao5/QGtCRGAZn8bxX9KlCrrWISIjSYAwCajIEGSPEZwPNMBoK8XD8Q= user@host-name

标识密钥 Identity Key #

标识密钥是一种私钥,在 SSH 公钥身份验证中用于授予访问服务器的权限。在 OpenSSH 中可以使用ssh-keygen工具生成,通常会生成一对密钥(私钥 - 公钥),如下图所示。

image

会话密钥 Session Key#

SSH 协议利用 Key Exchange 算法为每个会话或连接派生一个唯一的密钥,这个密钥被称为会话密钥 Session Key,常见的 Key Exchange 算法有 Diffie-HellmanElliptic-curve Diffie–Hellman

会话密钥在会话连接双方之间共享,这很容易受到中间人攻击。

向前保密性:由于使用了会话密钥,即使长期密钥(主机密钥)泄露,入侵者也无法解密之前的会话内容。

关于密钥的基础知识#

公钥 Public Key#

公钥是与私钥算法一起使用的密钥对的非秘密一半。公钥通常用于加密会话密钥验证数字签名,或加密可以用相应的私钥解密的数据。公钥和私钥是通过一种算法得到的一个密钥对 (即一个公钥和一个私钥),其中的一个向外界公开,称为公钥;另个自己保留,称为私钥。通过这种算法得到的密钥对能保证在世界范围内是唯一的。使用这个密钥对的时候,如果用其中一个密钥加密一段数据,必须用另一个密钥解密。如用公钥加密数据就必须用私钥解密,如果用私钥加密也必须用公钥解密,否则解密将不会成功。

在 SSH 中,公钥加密用于对计算机和用户进行身份验证。主机密钥对主机进行身份验证。授权密钥和身份密钥对用户进行身份验证。

私钥 Private Key#

在公钥密码系统中,私钥是用于对文档进行数字签名的密钥。在某些密码系统中,它还可用于解密使用公钥加密的数据。每个私钥都有一个对应的公钥。通常,公钥可以很容易地从私钥派生,但从公钥派生私钥在计算上是不可行的。

在 SSH 中,私钥用于对计算机和用户进行身份验证。主机密钥对服务器进行身份验证,标识密钥用作用户的身份验证凭据。

SSH 配置文件#

OpenSSH 客户端配置文件#

配置文件的保存位置:

  • Linux ~/.ssh/config/etc/ssh/ssh_config
  • Windows C:\Users\user\.ssh\config

通常情况下配置文件是不存在的,你可以手动创建它

  • Linux touch ~/.ssh/config&&chmod 600 ~/.ssh/config
  • Windows 到C:\Users\user\.ssh\路径下手动创建文本文件并删除.txt后缀

配置文件的结构#

Host hostname1
    SSH_OPTION value
    SSH_OPTION value

Host hostname2
    SSH_OPTION value

Host *
    SSH_OPTION value
  • config 的结构如上所示,是一块一块的。
  • 缩进其实不是必须的,但是有缩进非常有助于查看。
  • 每一块使用 Host 指令开始,每一个 Host 块可以针对一个或者多个需要匹配的内容(多个使用空格分隔),也可以采用下面这些特殊标识符:
    • *匹配 0 或者任意个字符。比如Host *匹配所有的 Hosts,192.168.0.*匹配192.168.0.0/24这个 subnet 下的 IP。
    • ?匹配一个字符。如10.10.0.? 匹配10.10.0.[0-9]
    • !取反,即不匹配。比如Host 10.10.0.* !10.10.0.5匹配10.10.0.0/24 subnet但是10.10.0.5除外。

匹配规则: SSH 客户端是从上往下匹配的,因此如果有多个 Host 匹配命中,其中定义的配置参数第一个出现的生效,比如第一个匹配配置组里面有 User 配置,最后匹配到的配置组里面也有,那是第一个匹配到的 User 会被实际使用。所以建议将比较具体的匹配放在上方,通用的放在后面 (比如针对某一个 ip 段的放在上面,针对所有的放在最后面)。

配置文件详解#

  • Host host-name 指定配置块,必配项
  • user username 指定登录用户,必配项
  • hostname 10.0.0.1 指定服务器地址,通常用 ip 地址,必配项
  • port 22 指定认证私钥文件,必配项
  • Identityfile ~/.ssh/id_rsa 指定本地认证私钥地址
  • IdentityFile ~/.ssh/id_rsa.pub 指定认证私钥文件
  • ForwardAgent yes 允许 ssh-agent 转发
  • ForwardX11 yes 允许许 X11 转发 X11 转发
  • ForwardX11Trusted yes 远程 X11 客户端将具有对原始 X11 显示器的完全访问权限。
  • DynamicForward 2000 指定通过安全通道转发的本地端口
  • RemoteForward 3000 指定远程主机上的一个 TCP 端口通过安全通道转发到本地主机上的指定主机和端口。第一个参数必须是:[bind_address:]port,第二个参数必须是host:port。SSH 隧道
  • LocalForward 指定本地机器上的一个 TCP 端口通过安全通道转发到远程机器上的指定主机和端口。第一个参数必须是\[bind\_address:]port,第二个参数必须是 host:port
  • ExitOnForwardFailure yes 当动态、隧道、本地和远程端口转发设置失败时,是否应终止连接。
  • ClearAllForwardings 指定清除在配置文件中或在命令行上指定的所有localremotedynamic端口发。
  • GatewayPorts 2001 指定是否允许远程主机连接到本地的端口
  • IdentitiesOnly no 指定 ssh 是否仅使用配置文件或命令行指定的私钥文件进行认证。值为yesno,默认为no,该情况可在 ssh-agent 提供了太多的认证文件时使用。
  • StrictHostKeyChecking ask
    • ask:默认值,第一次连接陌生服务器时提示是否添加,同时如果远程服务器公钥改变时拒绝连接;
    • yes:不会自动添加服务器公钥到~/.ssh/known_hosts中,同时如果远程服务器公钥改变时拒绝连接;
    • no:自动增加新的主机键到~/.ssh/known_hosts中。
  • BindAddress 10.0.0.1 指定使用本地计算机上的指定地址作为连接的源地址。
  • Protoco- 2 按首选项顺序指定协议版本。多个版本必须以逗号分隔。
  • Cipher <char> 在 SSH v1 中设置加密用的密码。
  • Ciphers <char>
    • 按首选项顺序指定 SSH v2 允许的密码。
    • 多个密码必须以逗号分隔。
    • 命令ssh -Q cipher可用于查询支持的密码。
  • HostKeyAlgorithms ssh-ed25519 指定客户端要使用的 SSH v2 的主机密钥算法,按优先级排序。
  • HostKeyAlias username 指定一个别名,当在密钥数据库文件中查找或保存主机钥匙时,使用该别名而不是真实的主机名称。
  • GlobalKnownHostsFile <path> #指定要用于全局主机密钥数据库的文件,而不是/etc/ssh/sh_known_hosts
  • HashKnownHosts yes 将主机名和地址添加到~/.ssh/known_hosts时应对其进行哈希处理。
  • Compression no 指定是否使用压缩。
  • CompressionLeve- 1 指定在启用压缩时要使用的压缩级别。
  • EscapeChar ~ 设置 escape 按键。
  • ConnectionAttempts 10 指定退出前要进行的尝试次数。
  • ConnectTimeout 10 指定连接到 SSH 服务器时使用的超时(以秒为单位),而不是使用默认系统 TCP 超时。
  • ControlMaster 3 允许通过单个网络连接共享多个会话。
  • ControlPath <path> #指定用于连接共享的控制 socket 的路径,或指定字符串none以禁用连接共享。
  • RhostsAuthentication no 设置是否使用基于 rhosts 的安全验证。
  • RhostsRSAAuthentication no 设置是否使用用 RSA 算法的基于 rhosts 的安全验证。
  • HostbasedAuthentication yes 指定是否使用用户主目录中的.rhosts.shosts文件以及全局配置中的/etc/hosts.equiv/etc/shosts.equiv,尝试基于 rhosts 的认证与公钥认证。
  • RSAAuthentication yes 设置是否使用 RSA 算法进行安全验证。
  • PasswordAuthentication yes 设置是否使用口令验证。
  • FallBackToRsh no 设置如果用 ssh 连接出现错误是否自动使用 rsh。
  • UseRsh no 设置是否在这台计算机上使用 rlogin/rsh。
  • BatchMode no 如果设为yes,passphrase/password(交互式输入口令)的提示将被禁止。当不能交互式输入口令的时候,这个选项对脚本文件和批处理任务十分有用。
  • CheckHostIP yes 设置 ssh 是否查看连接到服务器的主机的 IP 地址以防止 DNS 欺骗。建议设置为yes
  • StrictHostKeyChecking no 如果设置成yes,ssh 就不会自动把计算机的密匙加入$HOME/.ssh/known_hosts文件,并且一旦计算机的密匙发生了变化,就拒绝连接。
  • KbdInteractiveAuthentication yes 指定是否使用键盘交互式身份验证。这是密码身份验证、一次性密码和多重身份验证的常用方法。
  • KbdInteractiveDevices
  • LocalCommand ipconfig 指定成功连接到服务器后要在本地计算机上执行的命令。
  • LogLeve- ERROR 指定来自 ssh 的日志信息的粗略程度。可以是 QUIET,FATAL,ERROR,INFO,VERBOSE,DEBUG,DEBUG1,DEBUG2,DEBUG3。
  • Macs hmac-sha1 按优先顺序指定 Mac(消息验证码)算法,命令ssh -Q mac可以用来查询支持的 Mac 算法。
  • NoHostAuthenticationForLocalhost yes 如果主目录是跨机器共享的,就可以使用这个选项。在这种情况下,localhost 将指的是每台机器上的不同机器,而用户将得到许多关于改变主机密钥的警告。
  • PreferredAuthentications 指定客户端应尝试 SSH v2 身份验证方法的顺序。
  • ProxyCommand 指定用于连接到服务器的命令。SSH 客户端使用其标准输入和标准输出与代理命令进行通信,代理命令应将通信传递给 SSH 服务器。
  • PubkeyAuthentication yes 指定是否使用 SSH 密钥尝试公钥认证。
  • SendEnv 指定应该向服务器发送哪些环境变量。
  • ServerAliveCountMax 10 设置客户端发送的keepalive的数量,而客户端没有收到来自服务器的任何信息反馈。当达到这个阈值时,客户端将终止会话。
  • ServerAliveInterva- 5 指定向服务器发送keepalive信息的时间间隔。这些信息是通过加密通道发送的,用于检测服务器是否崩溃或网络是否中断。
  • TCPKeepAlive yes 是否向对方发送 TCP keepalives。这是在 TCP 协议层面上的操作。
  • Tunne- yes 请求在客户端和服务器之间进行设备转发。这用于通过 SSH 实现 VPN
  • TunnelDevice remote_tun 要打开 tun 的设备,local_tun 或 remote_tun
  • UsePrivilegedPort no 指定是否使用特权端口进行外发连接。
  • UserKnownHostsFile <path> 指定一个文件,用户的已知主机密钥数据库,而不是默认的~/.ssh/known_hosts
  • VerifyHostKeyDNS yes 指定是否使用 DNS 和 SSHFP 资源记录来验证远程密钥。
  • VisualHostKey yes 在登录时或对于未知主机钥匙,除了十六进制指纹字符串外,是否还打印远程主机钥匙指纹的 ASCII 艺术图。

Open SSH 服务器端配置文件#

OpenSSH 服务器在启动时读取配置文件,通常配置文件的保存位置:

  • Linux /etc/ssh/sshd_config
  • Windows C:\ProgramData\ssh\sshd_config

配置文件的关系#

image

配置详解#

  1. 关于 SSH Server 的整体设定,包含使用的 port 啦,以及使用的密码演算方式
  • Port 22 SSH 默认使用 22 这个 port
  • Protoco- 2,1 选择的 SSH 协议版本,可以是 1 也可以是 2,如果要同时支持两者,就必须要使用 2,1 这个分隔了
  • ListenAddress 10.0.0.1 只监听来自 10.0.0.1 的 SSH 联机。(假设有两个 IP 10.0.0.1 与 10.0.0.2 )
  • PidFile /var/run/sshd.pid 可以放置 SSHD 这个 PID 的档案,左列为默认值
  • LoginGraceTime 600 连接等待时间(单位秒)
  • Compression yes 是否可以使用压缩指令  
  1. 说明主机的 Private Key 放置的档案,默认使用下面的档案即可
  • HostKey /etc/ssh/ssh_host_key SSH v1 使用的私钥
  • HostKey /etc/ssh/ssh_host_rsa_key SSH v2 使用的 RSA 私钥
  • HostKey /etc/ssh/ssh_host_dsa_key SSH v2 使用的 DSA 私钥
  • KeyRegenerationInterva- 3600  重新建立主机密钥的时间间隔
  • ServerKeyBits 768  Server key 的长度
  1. 关于登录文件的讯息数据放置与 daemon 的名称
  • SyslogFacility AUTH  当有人使用 SSH 登入系统的时候,SSH 会记录信息在 daemon name 下,默认是以 AUTH 来设定的,即/var/log/secure里面,其它可用的 daemon name 为:DAEMON,USER,AUTH,LOCAL0,LOCAL1,LOCAL2,LOCAL3,LOCAL4,LOCAL5,
  • LogLeve- INFO  登录记录的等级
  1. 登入设定部分
  • PermitRootLogin no 是否允许 root 登入。默认是允许的,但是建议设定成 no
  • UserLogin no 在 SSH 底下本来就不接受 login 这个程序的登入
  • StrictModes yes 使用者的 host key 改变之后,Server 就不接受新的 SSH 连接
  • RSAAuthentication yes 是否完全使用 RSA 认证,仅针对 SSH v1
  • PubkeyAuthentication yes 是否允许 Public Key 只针对 SSH v2
  • AuthorizedKeysFile .ssh/authorized_keys 密钥身份认证的密钥路径
  1. 认证部分
  • RhostsAuthentication no 是否使用.rhosts,因为不安全了,所以通常禁用
  • IgnoreRhosts yes 是否取消使用~/.ssh/.rhosts
  • RhostsRSAAuthentication no 是否使用/etc/hosts.equiv中的 rhosts 配合 RSA 演算方式来进行认证,只针对 SSH v1
  • HostbasedAuthentication no 这个项目与上面的项目类似,只针对 SSH v2
  • IgnoreUserKnownHosts no  是否忽略/home/.ssh/known_hosts中记录的主机内容
  • PasswordAuthentication yes 是否开启密码验证
  • PermitEmptyPasswords no  是否允许以空的密码登入
  • ChallengeResponseAuthentication yes 挑战任何的密码认证,任何 login.conf 规定的认证方式,均可适用!
  • PAMAuthenticationViaKbdInt yes 是否启用其它的 PAM 模块!启用会导致 PasswordAuthentication 设定失效  
  1. 与 Kerberos 有关的参数设定
  • KerberosAuthentication no
  • KerberosOrLocalPasswd yes
  • KerberosTicketCleanup yes
  • KerberosTgtPassing no  
  1. 底下是有关在 X-Window 底下使用的相关设定
  • X11Forwarding yes
  • X11DisplayOffset 10
  • X11UseLocalhost yes
  1. 登入后的项目
  • PrintMotd no 登入后是否显示出一些信息,例如上次登入的时间、地点等等,默认是 yes
  • PrintLastLog yes  显示上次登入的信息,默认是 yes
  • KeepAlive yes  是否开启 keepalive
  • UsePrivilegeSeparation yes 使用者的权限设定项目
  • MaxStartups 10  同时允许尚未登入的联机会话数量(连上 SSH 但是尚未输入密码时,即联机会话)
  1. 关于拒绝连接的设定项目
  • DenyUsers test 设定拒绝登录的用户名称
  • DenyGroups test 设定拒绝登录的用户群组
  1. 关于 SFTP 服务的设定项目
  • Subsystem sftp /usr/lib/ssh/sftp-server

known_hosts#

known_hosts 中存储是已认证的远程主机 host key,每个 SSH Server 都有一个 secret, unique ID, called a host key。

known_hosts 的存储路径:

  • Linux: ~/.ssh/known_hosts
  • Windows:C:\Users\uesr\.ssh\known_hosts

当我们第一次通过 SSH 登录远程主机的时候,Client 端会有如下提示:

Host key not found from the list of known hosts.
Are you sure you want to continue connecting (yes/no)?

此时,如果我们选择 yes,那么该 host key 就会被加入到 Client 的 known_hosts 中,格式如下:

# domain name+encryption algorithm+host key
example.hostname.com ssh-rsa AAAAB4NzaC1yc2EAAAABIwAAAQEA。。。

为什么需要 known_hosts? 这个文件主要是通过 Client 和 Server 的双向认证,从而避免 #中间人攻击,每次 Client 向 Server 发起连接的时候,不仅仅 Server 要验证 Client 的合法性,Client 同样也需要验证 Server 的身份,SSH client 就是通过 known_hosts 中的 host key 来验证 Server 的身份的。

实用教程#

SSH 客户端与服务器端安装#

Linux 验证安装#

在大多数 Linux 系统中是默认安装好了的,你可以实用下面的命令检查。

  • 成功显示版本号,证明已安装 OpenSSH
  • 验证服务时原点是绿色的,证明 SSH 服务正在运行
#验证ssh版本
$ ssh -V
OpenSSH_8.2p1 Ubuntu-4ubuntu0.4, OpenSSL 1.1.1f  31 Mar 2020
#验证SSH服务状态
$ systemctl status sshd.service
 ssh.service - OpenBSD Secure Shell server
     Loaded: loaded (/lib/systemd/system/ssh.service; ena>
     Active: active (running) since Sun 2022-02-27 19:28:>
       Docs: man:sshd(8)
             man:sshd_config(5)
    Process: 796 ExecStartPre=/usr/sbin/sshd -t (code=exi>
   Main PID: 824 (sshd)
      Tasks: 1 (limit: 4491)
     Memory: 4.0M
     CGroup: /system.slice/ssh.service
             └─824 sshd: /usr/sbin/sshd -D [listener] 0 o>

مار 03 00:44:39 zac-ubuntu sshd[21852]: pam_unix(sshd:ses>
مار 03 00:44:39 zac-ubuntu sshd[21852]: pam_unix(sshd:ses>
مار 03 00:44:54 zac-ubuntu sshd[21917]: Accepted password>
مار 03 00:44:54 zac-ubuntu sshd[21917]: pam_unix(sshd:ses>
مار 03 00:45:02 zac-ubuntu sshd[21985]: Accepted password>
مار 03 00:45:02 zac-ubuntu sshd[21985]: pam_unix(sshd:ses>
مار 03 19:56:27 zac-ubuntu sshd[26728]: Accepted password>
مار 03 19:56:27 zac-ubuntu sshd[26728]: pam_unix(sshd:ses>
مار 03 21:28:46 zac-ubuntu sshd[28737]: Accepted password>
مار 03 21:28:46 zac-ubuntu sshd[28737]: pam_unix(sshd:ses>
lines 1-22/22 (END)

Linux 手动安装 SSH#

安装命令:

# arch
pacman -S openssh
# ubuntu
apt-get install openssh
# RHEL
yum install openssh

启动服务:

# 启动SSH守护进程
systemctl start sshd
# 开机自启
systemctl enable sshd

Windows 手动安装 SSH#

在 Window 10(版本 1809 及更高版本)开始支持 OpenSSH,若要安装 OpenSSH 组件:

  1. 打开 “设置”,选择 “应用”>“应用和功能”,然后选择 “可选功能” 。
  2. 扫描列表,查看是否已安装 OpenSSH 。 如果未安装,请在页面顶部选择 “添加功能”,然后:
  • 查找 “OpenSSH 客户端”,再单击 “安装”
  • 查找 “OpenSSH 服务器”,再单击 “安装” 设置完成后,回到 “应用”>“应用和功能” 和 “可选功能”,你应会看到已列出 OpenSSH 。

分步教程参考《Windows - 安装 SSH 服务器》

image

对于 Window 10(版本 1809 以下)以及 Windows 7 手动安装 OpenSSH

  1. 下载对用系统版本的安装文件;GitHub 下载连接
  2. 将下载好的安装.zip文件解压;
  3. 将解药好的文件夹整体复制到C:/Program Files/路径下,当然你可以放到你电脑上的任何你喜欢的路径下;
  4. 计算机(windows7) 或此电脑(windows10),右键 --> 属性 --> 高级系统设置 --> 环境变量 -- 系统变量,在此框里面找到Path进行编辑;

image

  1. windows7 系统编辑时候是以文本形式,所以就需要在最后先添加 “;” 英文分号,再把你安装路径C:\Program Files\OpenSSH-Win64粘贴进去;windows 10 系统添加比较方便,进到 Path 里面,点击新建直接粘贴进去;

image

详细教程请参考《Windows 安装 OpenSSH 支持 SSH》

在 Windows 上验证安装,打开cmd或者powershell

$ ssh -V
OpenSSH_for_Windows_8.1p1, LibreSSL 3.0.2

设置 SSH 服务开机自启动

image

SSH 端口号#

默认状态下,ssh 是工作在 tcp 22 端口。

在 SSH 的 C/S 模式中,SSH Server 会监听 22 端口,SSH Client 会使用随机端口号(1024~65535)与 SSH Server 建立连接。

如何更改 SSH Server 的默认端口#

找到 SSH 的配置文件:

  • 在 Linux 中:/etc/ssh/sshd_config
  • 在 Windows 中:C:\ProgramData\ssh\sshd_config
#Port 22

取消前面的注释#,将22修改为你想 SSH 工作的端口(请不要与其他端口冲突)。

连接 SSH 时使用指定端口号#

ssh -p <port-number> user@ip-address
sftp -P <port-number> user@ip-address  #注意P使用大写字母

SFTP 使用 SSH 协议传输数据,所以共用端口号

密钥生成工具ssh-keygen#

ssh-keygen是用于创建新的密钥对的工具。即上面章节中提及的授权密钥与标识密钥组成的密钥对。

以下是操作示例:

$ ssh-keygen 
Generating public/private rsa key pair. 
Enter file in which to save the key (/home/user/.ssh/id_rsa):   #你可以在这一步中指定密钥存储的路径
Enter passphrase (empty for no passphrase):   #你可以在这一步指定一个密码(passphrase)用于保护密钥
Enter same passphrase again:   #再次确认上一步的密码(passphrase)
Your identification has been saved in /home/user/.ssh/id_rsa.   #提示你的私钥保存路径
Your public key has been saved in /home/user/.ssh/id_rsa.pub.   #提示你的公钥保存路径
The key fingerprint is: SHA256:Up6KjbnEV4Hgfo75YM393QdQsK3Z0aTNBz0DoirrW+c user@host 
The key's random art image is: 
+---[RSA 2048]----+ 
|    .      ..oo..| 
|   . . .  . .o.X.| 
|    . . o.  ..+ B| 
|   .   o.o  .+ ..| 
|    ..o.S   o..  | 
|   . %o=      .  | 
|    @.B...     . | 
|   o.=. o. . .  .| 
|    .oo  E. . .. | 
+----[SHA256]-----+ 
host (11:40) ~>

上面所有的步骤都可以留空,不用填写任何内容

选择算法和密钥大小#

在上面的 “The key's random art image is:” 下的图中我们可以看到RSA 2048RSA就是密钥算法;2048就是密钥大小。

ssh-keygen -t <arithmetic> -b <size>   #-t后面指定算法名;-b后面指定密钥大小

SSH 支持多种密钥算法:

  • rsa 是最早的公钥密码系统之一,被广泛用于安全数据传输。它的安全性取决于整数分解,因此永远不需要安全的 RNG(随机数生成器)。与 DSA 相比,RSA 的签名验证速度更快,但生成速度较慢。建议密钥大小至少为 2048 位。4096 位更好。
  • dsa 一种旧的美国政府数字签名算法。它基于计算离散对数的难度,与 RSA 相比,DSA 的签名生成速度更快,但验证速度较慢。通常密钥大小 1024。
  • ecdsa 是 DSA(数字签名算法)的椭圆曲线实现。椭圆曲线密码术能够以较小的密钥提供与 RSA 相对相同的安全级别。它还具有 DSA 对不良 RNG 敏感的缺点。支持三种密钥大小:256、384 和 521 位,建议 521 位。
  • ed25519 是 EdDSA 签名方案,但使用 SHA-512/256 和 Curve25519;它是一条安全的椭圆形曲线,比 DSA,ECDSA 和 EdDSA 提供更好的安全性,并且具有更好的性能。这是 OpenSSH 中添加的新算法,仅少量的客户端支持。
  1. 根据数学特性,这四种类型又可以分为两大类,dsa/rsa 是一类,ecdsa/ed25519 是一类,后者算法更先进。
  2. dsa 因为安全问题,已不再使用了。
  3. ecdsa 因为政治原因和技术原因,也不推荐使用。
  4. rsa 是目前兼容性最好的,应用最广泛的 key 类型,在用 ssh-keygen 工具生成 key 的时候,默认使用的也是这种类型。不过在生成 key 时,如果指定的 key size 太小的话,也是有安全问题的,推荐 key size 是 3072 或更大。
  5. ed25519 是目前最安全、加解密速度最快的 key 类型,由于其数学特性,它的 key 的长度比 rsa 小很多,优先推荐使用。它目前唯一的问题就是兼容性,即在旧版本的 ssh 工具集中可能无法使用。不过据我目前测试,还没有发现此类问题。 -- 摘自《RSA,DSA,ECDSA,EdDSA 和 Ed25519 的区别》

使用ssh-keygen创建主机密钥#

该工具还用于创建主机密钥。主机密钥只是普通的 SSH 密钥对。对于上面提到的四种算法,每台主机都可以根据这四种算法各生成一对密钥。在 Linux 中示例如下:

  • /etc/ssh/ssh_host_dsa_key
  • /etc/ssh/ssh_host_dsa_key.pub
  • /etc/ssh/ssh_host_ecdsa_key
  • /etc/ssh/ssh_host_ecdsa_key.pub
  • /etc/ssh/ssh_host_ed25519_key
  • /etc/ssh/ssh_host_ed25519_key.pub
  • /etc/ssh/ssh_host_rsa_key
  • /etc/ssh/ssh_host_rsa_key.pub

主机密钥通常在安装 SSH 服务时自动生成。它们也可以随时再生,如果主机密钥发生更改,客户端可能会发出有关已更改密钥的警告。

将密钥复制到服务器的工具ssh-copy-id#

除了手动将客户端id-rsa.pub中的授权密钥复制到服务器端的 authorized_keys 内以外,你还可以使用ssh-copy-id工具在命令行中完成此操作。

首先确认你已经在客户端生成了一对密钥(公钥 - 密钥),下面是复制命令:

ssh-copy-id  -i <pub_key path> user@serverhost   #<pub_key path>:公钥的文件路径

执行成功后客户端的授权密钥就出现在了服务器端的 authorized_keys 内

在 Windows 上是没有ssh-copy-id命令的,你可以参考《windows 无法使用 ssh-copy-id 解决办法》

实现 SSH 免密码登录(公钥身份认证)#

准备条件#

  • 安装好 SSH 客户端与服务器端

简单配置服务器端#

  1. 为你要登录的用户 user 创建~/.ssh目录以及~/.ssh/authorized_keys文件。并设置正确的权限(否则 SSH 会拒绝连接):
# 确认当前用户为harttle
whoami
# 创建.ssh目录
mkdir ~/.ssh
chmod 700 ~/.ssh
# 创建对方公钥文件
touch ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

以上命令适用于 Linux,在 Windows 上找到C:\Users\user\.ssh\目录,通常authorized_keys文件会自动生成,如果没有可以手动创建一个文本文件并将名称改为authorized_keys(注意:不能有.txt或其他后缀)。

  1. 将客户端生成的公钥(授权密钥)~/.ssh/id_rsa.pub中的内容复制到服务器端的~/.ssh/authorized_keys文件中。
cat ~/.ssh/id_rsa.pub | ssh user 'cat >> .ssh/authorized_keys'

在 Linux 上你也可以使用ssh-copy-id工具来复制密钥;

现在你就可以通过以下命令实现免认证登陆了

ssh <user>@<ipaddress>

在以 Windows 为服务器端时可能无法配置成功,参考 7.4 Windows 配置自动登录的问题

SSH 身份认证代理ssh agent#

ssh-agent是一种控制用来保存公钥身份验证所使用的私钥的程序。

本质上ssh-agent就是一个密钥管理器,运行ssh-agent以后,使用 ssh-add 将私钥交给ssh-agent保管,其他程序需要身份验证的时候可以将验证申请交给ssh-agent来完成整个认证过程。

ssh agent的使用场景#

  • 使用不同的密钥连接到不同的主机时,需要手动指定对应的密钥。ssh-agent 可以帮助我们选择对应的密钥进行认证,不用手动指定密钥即可进行连接。

    如果我们在使用ssh-keygen生成密钥对时没有使用默认名称 id_rsa 作为密钥名称,而是使用其他名称,比如 is_rsa_test 作为密钥名称,那么当我们使用该密钥对远程连接服务器ssh user@host 依然会提示输入服务器 host 的密码。

    因为 ssh 基于密钥进行认证时,默认会使用~/.ssh/id_rsa进行认证,当你使用非默认名称的私钥进行认证时,需要手动指明对应的私钥,如果不指明对应的私钥,ssh 仍然会默认使用~/.ssh/id_rsa进行认证,所以无法认证成功。

    虽然可以通过-i选项指定对应的私钥文件进行认证,ssh -i ~/.ssh/id_rsa_test user@host,但是如果有很多密钥对,使用起来就过于繁琐。而ssh-agent则可以帮我们管理这些密钥,避免手动指定密钥,ssh-agent会帮助我们选择对应的密钥。使用ssh-add ~/.ssh/id_rsa_test将密钥加入到ssh-agent中。

  • 当私钥设置了密码,我们又需要频繁的使用私钥进行认证时,ssh-agent 可以帮助我们免去重复的输入密码的操作。

    如果生成密钥对,同时指定私钥的密码,每次使用私钥进行认证连接是,都会要求输入私钥密码,如果你在当前 ssh 会话中需要反复的连接到服务器,那么反复的输入复杂的私钥密码,的确会比较麻烦,ssh-agent 可以帮助我们,在一个 ssh 会话中,只要输入一次私钥密码,在同一 ssh 会话中之后再次使用到相同的私钥时,即可不用再次输入对应密码。

如何使用ssh agent#

  1. 开启ssh-agent进程

    进入 ssh-agent 环境:

    #在Linux上
    ssh-agent bash  
    ssh-agent $SHELL
    eval $(ssh-agent)
    #在Windows
    ssh-agent
    #在Windows上也可以到服务里面手动启动OpenSSH Authentication Agent服务
    

    此时会发现系统多增加了一个 ssh-agent 进程

    ssh-agent参数

    参数描述
    -a <bind_address>将代理绑定到 Unix 域套接字绑定地址
    -d调试模式
    -D前台模式。
    -k把 ssh-agent 进程杀掉(在 Windows 上无效)
    -s生成 Bourne shell 风格的命令输出
    -E <fingerprint_hash>指定显示密钥指纹时使用的哈希算法。md5 或 sha256(默认值)
  2. 将密钥添加到ssh-agent

    ssh-add <options> <path>  #<path>密钥的路径
    

    ssh-add参数

    参数描述
    -l列出当前agent中所有的密钥指纹
    -L列出当前agent中所有的公钥参数
    -E <fingerprint_hash>指定显示密钥指纹时使用的哈希算法。md5 或 sha256(默认值)
    -k添加密钥到agent或从agent中移除密钥时跳过证书
    -K从 FIDO 身份验证器加载驻留密钥
    -c使用添加的密钥进行身份认证之前需经过确认
    -t添加密钥时设置生存周期(单位:秒,可以在sshd_config中添加TIME FORMATS h来更改时间单位,支持 s m h d w)
    -T通过对每个私钥执行签名和验证操作来测试与指定的私钥是否可用
    -dagent中删除密钥
    -Dagent中删除全部密钥
    -x使用密码锁定agent,即暂停agent管理密钥
    -X使用密码解锁agent
    -q操作成功后保持静默
    -h添加密钥时只用于特定主机或特定目标
    -H指定一个 hosts 文件用于此密钥在身份认证时查找主机密钥。可以多次指定多个 hosts 文件,用,隔开

其他设置#

简化登录#

已经配置了免密码登录(公钥身份认证),但是如果你的用户名很复杂(例如用户名是邮箱地址等),或者不想及服务器的 IP 地址,那么可以更改配置文件来简化流程。

找到配置文件的路径:

  • Linux~/.ssh/config
  • WindowsC:\Users\Lin\.ssh\config

添加下面的内容到config文件中

Host <name>  #自定义的名称
  HostName <ipaddress>  #服务器端主机名称或IP地址
  UserName <user>  #登陆时使用的用户名

现在你就可以使用简化的命令了

ssh <name>

你还可以参考客户端配置文件详解来添加你需要的功能。

安全文件传输工具#

安全文件传输 SFTP#

sftp 是一个文件传输程序,类似于 ftp,它使用 ssh 加密执行所有操作。它还可以使用 ssh 的公钥身份验证和压缩功能。 可以

  • 连接命令

    sftp user@host:path
    #URI格式为
    sftp://user@host:port/path
    

    sftp命令参数

    参数描述
    -a尝试继续中断的传输,而不是覆盖文件的现有部分
    -b批处理模式
    -B <buffer_size>指定传输文件时使用的缓存大小。较大的缓存需要较少的往返行程,但内存消耗较高。默认值为 32768 字节
    -l限制带宽,以 Kbit/s 为单位指定
    -P指定要连接的远程主机上的端口
    -p保留原始的文件的修改时间、访问时间和模式等
    -4与 ssh 命令相同
    -6与 ssh 命令相同
    -A与 ssh 命令相同
    -C与 ssh 命令相同
    -F与 ssh 命令相同
    -i与 ssh 命令相同
    -J与 ssh 命令相同
  • 交互式命令

    sftp> cd <path> #打开路径<path>
    sftp> bye  #退出SFTP
    sftp> quit  #退出SFTP
    sftp> exit  #退出SFTP
    sftp> help  #显示帮助文本
    sftp> ?  #显示帮助文本
    sftp> ls <path>  #显示当前目录或<path>目录中的目录和文件
    sftp> ls -1 <path>  #单列显示当前目录或<path>目录
    sftp> ls -a <path>  #列出当前目录或<path>目录以.开头的文件
    sftp> ls -f <path>  #不使用首字母排序当前目录或<path>目录
    sftp> ls -l <path>  #显示当前目录或<path>目录中的文件和目录的权限、所有权等详细信息
    sftp> ls -n <path>  #显示当前目录或<path>目录中的文件和目录的权限、所有权等详细信息,其中用户和组信息以数字形式显示
    sftp> ls -r <path>  #使用首字母反向排序当前目录或<path>目录
    sftp> ls -S <path>  #按文件大小排序当前目录或<path>目录
    sftp> ls -t <path>  #按上次修改时间排序当前目录或<path>目录
    sftp> lls <path>  #显示当前目录或<path>目录中的目录
    sftp> chgrp <group> <path>  #将<path>文件的文件组修改为<group>
    sftp> chmod <mode> <path>  #将<path>文件的模式修改为<mode>
    sftp> chown <owner> <path>  #将<path>文件的所有者修改为<owner>
    sftp> df -h <path>  #显示保存当前目录或<path>目录的文件系统的使用信息
    sftp> df -i <path>  #显示保存当前目录或<path>目录的文件系统的inode信息
    sftp> get <remote-path> <local path>  #检索<remote-path>文件或目录并将其储存到本地<local path>,如果未指定本地路径名,则会为其指定与远程计算机上相同的名称。
    sftp> get -a <remote-path> <local path>  #尝试恢复现有文件的部分传输
    sftp> get -p <remote-path> <local path>  #复制文件权限和访问时间
    sftp> lcd <path>  #将本地目录更改为<path>或用户主目录
    sftp> lpwd  #打印本地工作目录
    sftp> pwd  #打印远程工作目录
    sftp> lmkdir <path>  #创建一个本地目录<path>
    sftp> mkdir <path>  #创建一个远程目录<path>
    sftp> rename <path1> <path2>  #将远程文件从<path1>重命名为<path2>
    sftp> ln <path1> <path2>  #创建从<path1>到<path2>的链接
    sftp> ln -s <path1> <path2>  #创建从<path1>到<path2>的硬链接
    sftp> put <local path> <remote path>  #上载本地<local path>并将其存储在远程<remote path>,如果未指定远程路径名,则会为其指定与本地计算机上相同的名称。
    sftp> put -a <local path> <remote path>  #尝试恢复现有文件的部分传输
    sftp> put -ap <local path> <remote path>  #复制文件权限和访问时间
    sftp> reget <remote-path> <local path>  #等效get -a
    sftp> reput <local path> <remote path>  #等效put -a
    sftp> rm <path>  #删除指定的远程文件<path>
    sftp> rmdir <path>  #删除指定的远程目录<path>
    sftp> version  #显示当前sftp协议版本
    sftp> !  #跳转到本地shell
    sftp> ! <command>  #在本地shell执行命令<command>
    

安全文件复制 SCP#

SCP 是用于在计算机之间复制文件的程序,它使用 SSH 协议。默认情况下它包含在 SSH 软件包中

SCP 基本用法:

  1. 从本地复制到远程主机

    • 指定远程目录,复制完成后文件名称不变
    scp local_file remote_username@remote_ip:remote_folder  #执行后只询问密码
    scp local_file remote_ip:remote_folder #执行后询问用户名和密码
    
    • 指定文件名称,复制完成后改为指定文件名称
    scp local_file remote_username@remote_ip:remote_file #执行后只询问密码
    scp local_file remote_ip:remote_file #执行后询问用户名和密码
    
    • 复制目录-r
    scp -r local_folder remote_username@remote_ip:remote_folder #执行后只询问密码
    scp -r local_folder remote_ip:remote_folder #执行后询问用户名和密码
    
  2. 从远程主机复制到本地

    只要将从本地复制到远程的命令的后 2 个参数调换顺序即可

    scp remote_username@remote_ip:remote_file local_file 
    scp -r remote_username@remote_ip:remote_folder local_folder
    
  3. 指定端口号-P

    使用大写P

    #scp命令使用端口号4588
    scp -P 4588 remote_username@remote_ip:remote_folder
    
  4. 免认证

    配置 SSH 公钥身份验证后即可实现免认证。

SSH 命令总结#

语法格式ssh [参数] [远程主机]

参数描述
-1强制使用 ssh 协议版本 1
-2强制使用 ssh 协议版本 2
-4强制使用 IPv4 地址
-6强制使用 IPv6 地址
-A开启认证代理连接转发功能
-a关闭认证代理连接转发功能
-b <IP 地址>使用本机指定的地址作为对位连接的源 IP 地址
-C请求压缩所有数据
-F <配置文件>指定 ssh 指令的配置文件,默认的配置文件为 “/etc/ssh/ssh_config”
-f后台执行 ssh 指令
-g允许远程主机连接本机的转发端口
-i <身份文件>指定身份文件(即私钥文件)
-l <登录名>指定连接远程服务器的登录用户名
-N不执行远程指令
-o <选项>指定配置选项
-p <端口>指定远程服务器上的端口
-q静默模式,所有的警告和诊断信息被禁止输出
-X开启 X11 转发功能
-x关闭 X11 转发功能
-y开启信任 X11 转发功能
#示例
ssh -p <port-number> -- user -i C:\Users\user\.ssh\custom_config <ip-address>

常见问题#

SSH 中的中间人攻击#

黑客和恶意软件会攻击路由器、DSL 解调制器和 WiFi 路由器,在上面安装恶意软件来执行中间人攻击,安装了恶意软件的设备被称为攻击工具

在 SSH 协议中,主机密钥只能由 root 用户访问。如果攻击者获得了服务器的 root 访问权限,他当然可以获得主机密钥的副本。

一旦攻击者获取到服务器主机密钥的副本,当客户端连接时,就可以在攻击工具上,冒充 SSH 服务端与客户端建立连接,骗取服务器端的密码或密钥。

然后再攻击工具上充当客户端,与服务器建立另一个加密连接。

X11 转发 X11-Forwarding#

什么是 X11-forwarding?#

X11 中的 X 指的就是 X 协议;11 指的是采用 X 协议的第 11 个版本。 X11-forwarding 说的简单明白点就是:可以通过一个支持 X Server 的 SSH 客户端,例如:MobaXterm。 连接到远程 Linux 服务器,可以在本地通过 MobaXterm 运行操作一个远程 Linux 服务器上有图形界面的程序。

X 协议原理简介#

image

Linux 系统本身是没有图形化界面的,所谓的图形化界面系统只不过中 Linux 下的应用程序,所有的 Linux 系统的图形化界面应用程序底层都是基于 X 协议。

X 协议由 X server 和 X client 组成:

  • server 管理主机上与显示相关的硬件设置(如显卡、硬盘、鼠标等),它负责屏幕画面的绘制与显示,以及将输入设置(如键盘、鼠标)的动作告知 X client。
  • X client (即 X 应用程序) 则主要负责事件的处理(即程序的逻辑)。

举个例子,如果用户点击了鼠标左键,因为鼠标归 X server 管理,于是 X server 就捕捉到了鼠标点击这个动作,然后它将这个动作告诉 X client,因为 X client 负责程序逻辑,于是 X client 就根据程序预先设定的逻辑(例如画一个圆),告诉 X server 说:“请在鼠标点击的位置,画一个圆”。最后,X server 就响应 X client 的请求,在鼠标点击的位置,绘制并显示出一个圆。

支持 X11-forwarding 的 SSH 客户端#

  • XShell- 6
  • MobaXterm 11

SCP 和 SFTP 相同点和区别#

都是使用 SSH 协议来传输文件的。登录时的用户信息都是经过 SSH 加密后才传输的,所以说 SCP 和 SFTP 实现了安全的文件传输。 SFTP 和 FTP 命令相似,SFTP 和 FTP 的使用方法也类似。SCP 和 SFTP 的共同之处在于(使用 SSH 将文件加密才传输的

SCP 和 SFTP 的不同之处:

  • SCP 比较简单,是轻量级的,SFTP 的功能则比较多。
  • SFTP 在文件传输过程中中断的话,连接后还可以继续传输,但 SCP 不行。

Windows 配置自动登录的问题#

以 Windows 作为服务端并按照 6.5 实现 SSH 免密码登录(公钥身份认证)中的步骤配置时,在连接时依然要求输入密码。

我尝试重启了服务端的OpenSSH SSH Server服务,依然没有效果。

使用ssh -vvv查看调试信息

debug3: send packet: type 50
debug2: we sent a keyboard-interactive packet, wait for reply
debug3: receive packet: type 51 
debug1: Authentications that can continue: publickey,password,keyboard-interactive

这是以 Ubuntu 为服务器端自动登录成功的调试信息

debug3: sign_and_send_pubkey: signing using rsa-sha2-512
debug3: send packet: type 50
debug3: receive packet: type 52
debug1: Authentication succeeded (publickey).
Authenticated to 10.0.0.20 ([10.0.0.20]:2000).

可以看出在以 Windows 为服务器端时,客户端发送了密钥,但是服务器端并没有回应。

可以通过阿里云盘获取完整的调试信息

SSH 隧道#

SSH 隧道即 SSH 端口转发,在 SSH 客户端与 SSH 服务端之间建立一个隧道,将网络数据通过该隧道转发至指定端口,从而进行网络通信。SSH 隧道自动提供了相应的加密及解密服务,保证了数据传输的安全性。

SSH 隧道有三种端口转发模式:本地端口转发(Local Port Forwarding)、远程端口转发(Remote Port Forwarding)以及动态端口转发(Dynamic Port Forwarding)。对于本地 / 远程端口转发,两者的方向恰好相反。连接云手机时,使用的是本地端口转发,因此本文着重介绍本地端口转发的工作原理。

假设本地主机 A1 为 SSH 客户端,远端云主机 B1 为 SSH 服务端。从 A1 主机通过 SSH 登录 B1 主机,指定不同的端口转发选项(-L、-R 和 - D),即可在 A1 与 B1 之间建立 SSH 隧道,从而进行不同的端口转发。

应用场景

远端云主机 B1 上运行了一个服务,端口为 2000,本地主机 A1 需要访问这个服务。假设云主机 B1 的 IP 为 122.x.x.x,则该服务的访问地址为:http://122.x.x.x:2000

为什么需要本地端口转发?

一般来讲,云主机的防火墙默认只开启了 22 端口,如果需要访问 2000 端口,则需要修改防火墙。为了保证安全,防火墙需要配置允许访问的 IP 地址。但是,云主机的公网 IP 通常是网络提供商动态分配的,如果变更公网 IP 地址,防火墙配置就需要经常修改,造成不必要的麻烦。

什么是本地端口转发?

本地端口转发,是将发送到本地端口的请求,转发到目标端口,这样就可以通过访问本地端口,来访问目标端口的服务。使用 -L 选项,就可以指定需要转发的端口,语法如下:

ssh -L 本地端口:目标地址:目标端口

例如:

ssh -L 3000:localhost:2000 root 122.x.x.x

表示在本地主机 A1 登录远端云主机 B1 ,通过本地端口转发,将发送到本地主机 A1 端口 3000 的请求,转发到远端云主机 B1 的 2000 端口。

这样,在本地主机 A1 上可以通过访问 http://122.x.x.x:2000 来访问远端云主机 B1 上的服务。

参考#

  1. 《使用 OpenSSH 管理 Windows》🔗
  2. 《SSH 协议基本原理及 wireshark 抓包分析》🔗
  3. 《SSH 技术白皮书》🔗
  4. SSH 学院🔗
  5. 《SSH 协议解析及 wireshark 抓包分析》🔗
  6. 《ssh 两种认证方式的原理介绍》🔗
  7. 《图解 SSH 原理》🔗
  8. 《windows 无法使用 ssh-copy-id 解决办法》🔗
  9. 《RSA,DSA,ECDSA,EdDSA 和 Ed25519 的区别》🔗
  10. 《ssh 使用的 RSA,DSA 和 ECDSA 密钥之间有什么区别?》🔗
  11. 《SCP 和 SFTP 相同点和区别》🔗
  12. 《Windows 安装 SSH 服务器》🔗
  13. 《Windows 安装 OpenSSH 支持 SSH》🔗
  14. 《配置 SSH 免密码登录(Public Key)》🔗
  15. 《OpenSSH 手册》🔗
  16. 《ssh 代理转发介绍以及应用场景》🔗
  17. 《Linux 学习笔记 5 - ssh-agent 详解》🔗
加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。