SSH 概述#
SSH 是一种协议#
- Secure Shell(安全外壳协议,简称 SSH)是一种加密的网络传输协议。
- SSH 通过在网络中创建安全隧道来实现 SSH客户端与服务器之间的_连接_。
- SSH 最常见的用途是远程登录系统,人们通常利用 SSH 来传输命令行界面和远程执行命令。
OpenSSH 开放源代码版本#
OpenSSH 是安全 Shell (SSH) 工具的开放源代码版本,Linux 及其他非 Windows 系统的管理员使用此类工具跨平台管理远程系统。
常见的 SSH 工具#
名称 | 描述 | 支持平台 | 推荐 |
---|---|---|---|
PuTTY(Free Windows) | 免费开源的 SSH 终端工具 | Windows | ⭐⭐⭐ |
WinSCP | SCP 协议的文件传输工具 | 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
将加密隧道复用为若干逻辑信道。它建立在验证协议之上。
SSH 工作流#
通过 Wireshark 抓 包分析各个阶段#
TCP 三次握手#
SSH 服务器端在 22 端口侦听客户端的连接请求,接收到客户端的连接建立请求后,与客户端进行三次握手,建立起一条 TCP 连接,后续的所有报文交互都在这个 TCP 连接之上进行。
版本协商#
服务器和客户端都会向对端发送自己支持的版本号。服务器端和客户端收到对端发送过来的版本后,与本端的版本号进行比较,双方都支持的最高版本号即为协商出的版本号。
算法协商#
- 客户端和服务器端都将自己支持的算法列表发送给对方;
- 双方依次协商每一种算法(密钥交换算法、加密算法等)。每种算法的协商过程均为:从客户端的算法列表中取出第一个算法,在服务器端的列表中查找相应的算法,如果匹配上相同的算法,则该算法协商成功;否则继续从客户端算法列表中取出下一个算法,在服务器端的算法列表中匹配,直到匹配成功。如果客户端支持的算法全部匹配失败,则该算法协商失败。
- 某一种算法协商成功后,继续按照上述方法协商其他的算法,直到所有算法都协商成功;如果某一种算法协商失败,则客户端和服务器之间的算法协商失败,服务器断开与客户端的连接。
在algorithms
包含了所有需要协商的算法
NO. | 描述 | 解释 |
---|---|---|
1 | kex_algorithms | 密钥交换算法 Key Exchange,里边包含了 D-H 算法,用于生成会话密钥 |
2 | server_host_key_algorithms | 服务器主机密钥算法 Host Key,用于生成密钥对 |
3 | encryption_algorithms_client_to_server | 对称加密算法,常用的有aes128-cbc,3des-cbc |
4 | mac_algorithms_client_to_server | Mac 算法,主要用于保证数据完整性 |
5 | compression_algorithms_client_to_server | 压缩算法 |
密钥交换#
客户端生成一个临时密钥 ephemera- public key 发送给服务器端 **【??】**
服务端与客户端使用 Diffie-Hellman 算法生成会话密钥 Session key。
在这个包中,服务器端将主机密钥 Host Key、会话密钥 Session key、签名等一同发送给客户端。
客户端回复一个 New Key,接下来进入加密通信。
接下来的会话过程全程加密,从抓包中已经看不到任何铭文信息了。
用户认证#
- 客户端向服务器端发送认证请求报文,其中携带的认证方式为 “none”。
- 服务器收到 none 方式认证请求,回复认证挑战报文,其中携带服务器支持、且需要该用户完成的认证方式列表。
- 客户端从服务器发送给自己的认证方式列表中选择某种认证方式,向服务器发起认证请求,认证请求中包含用户名、认证方法、与该认证方法相关的内容:
- 密码认证方式中,内容为用户的密码;
- 公钥认证方式中,内容为用户本地密钥对的公钥部分(公钥验证阶段)或者数字签名(数字签名验证阶段)。
- 服务器接收到客户端的认证请求,验证客户端的认证信息:
- 密码认证方式:服务器将客户端发送的用户名和密码信息,与设备上或者远程认证服务器上保存的用户名和密码进行比较,从而判断认证成功或失败。
- 公钥认证方式:服务器对公钥进行合法性检查,如果不合法,则认证失败;否则,服务器利用数字签名对客户端进行认证,从而判断认证成功或失败。
- 服务器根据本端上该用户的配置,以及用户认证的完成情况,决定是否需要客户端继续认证,分为以下几种情况:
- 如果该种认证方式认证成功,且该用户不需要继续完成其他认证,则服务器回复认证成功消息,认证过程顺利完成。
- 如果该种认证方式认证成功,但该用户还需要继续完成其他认证,则回复认证失败消息,继续向客户端发出认证挑战,在报文中携带服务器需要客户端继续完成的认证方式列表;
- 如果该种认证方式认证失败,用户的认证次数尚未到达认证次数的最大值,服务器继续向客户端发送认证挑战;
- 如果该种认证方式认证失败,且用户的认证次数达到认证次数的最大值,用户认证失败,服务器断开和客户端之间的连接。
服务请求#
SSH 协议支持多种应用服务。用户成功完成认证后,SSH 客户端向服务器端发起服务请求,请求服务器提供某种应用。
服务请求的过程为:
- 客户端发送
SSH_MSG_CHANNEL_OPEN
消息,请求与服务器建立会话通道 session; - 服务器端收到
SSH_MSG_CHANNEL_OPEN
消息后,如果支持该通道类型,则回复SSH_MSG_CHANNEL_OPEN_CONFIRMATION
消息,从而建立会话通道; - 会话通道建立之后,客户端可以申请在通道上进行 shell 或 subsystem 类型的会话,分别对应 SSH 和 SFTP 两种类型的服务。
SSH 协议安全性机制#
加密通道#
所谓加密通道,是指发送方在发送数据前,使用加密密钥对数据进行加密,然后将数据发送给对方;接收方接收到数据后,利用解密密钥从密文中获取明文。
加解密算法分为两类:
- 对称密钥算法:数据加密和解密时使用相同的密钥和相同的算法。
- 非对称密钥算法:数据加密和解密时使用不同的密钥,一个是公开的公钥,一个是由用户秘密保存的私钥。
由于非对称密钥算法比较耗时,一般多用于数字签名以及身份认证。SSH 加密通道上的数据加解密使用对称密钥算法,目前主要支持的算法有 DES、3DES、AES 等,这些算法都可以有效地防止交互数据被窃听,而且由于采用了初始化向量保护,可以防止类似于密码流复用等密码分析工具的攻击。
密钥交换算法#
对称密钥算法要求解密密钥和加密密钥完全一致,才能顺利从密文中解密得到明文。因此,要建立加密通道,必须先在通信双方部署一致的加解密密钥。部署加解密密钥的方式有多种:手工配置和第三方机构分配等。手工配置的方式扩展性差,只适合一些小型的本地网络;使用第三方机构分配密钥的方式,需要额外的第三方服务器,而且密钥在网络中传输容易被窃听。
SSH 协议使用一种安全的方式在通信双方部署密钥:密钥交换算法。利用密钥交换算法可以在通信双方动态地产生密钥,这个密钥只能被通信的双方获得,任何第三者都无法窃听,这就在源头上保证了加解密使用密钥的安全性,很好地解决了密钥分发问题。
密钥交换算法的基本原理#
- 客户端随机选择一个私钥 ,计算出 ,将计算出的 发送给服务器端。其中, 是一个很大的素数, 是 的素根。 和 是双方共有的一对参数,协议允许双方通过协商获得相同的 和 参数。
- 服务器也随机生成一个私钥 ,计算出 ,也将计算出的 发送给客户端。
- 服务器接收到客户端发送过来的,按照下面的公式计算出密钥:
- 客户端收到服务器端发送过来的 ,同样按照下面的公式计算出密钥:
通过上面的方法,客户端和服务器端就可以获得相同的密钥。
由上面的分析可以看出,密钥交换算法的安全性建立在计算离散对数的难度之上。算式中,由 X 计算 Y 是很容易的,但是要由 Y 计算 X 是非常困难的。在密钥交换算法中对外公开的只有 、、 和,私钥和是保密的,其他用户即便获取了 、、 和也很难推断出私钥和,从而保证了密钥的安全性。
密钥交换算法具有如下优势:
- 扩展性更好,不需要网络管理员的多余配置;
- 交换得到的密钥是保存在内存中,不易被读取和篡改;
- 每个连接都会动态生成一次新的密钥,安全性更高。
用户认证机制#
基于密码的安全验证#
使用自动生成的公钥 - 私钥对来简单地加密网络连接,随后使用密码认证进行登录。具体过程如下:
- 客户端发送登录请求,
ssh user@hostname
- 服务器接受请求,将服务器的公钥 server_rsa.pub 发送给客户端
- 客户端输入密码,密码使用 server_rsa.pub 加密后发送给服务器(敏感信息安全传输)
- 服务器接受加密后的密码,使用服务器私钥 server_rsa 解密,匹配认证密码是否合法
至此,身份认证通过,然后是交换会话密钥(对称加密)
- 客户端生成会话数据加密 session_key, 使用 server_rsa.pub 加密后传输给服务器(会话密钥)
- 服务器获取到后使用 server_rsa 解密,得到 session_key
使用会话密钥对之后传递的数据进行加密。注:使用对称加密效率高。
- 客户端和服务器通过 session_key 进行会话数据安全传输
但是,这种认证方式无法避免中间人攻击,可能会有别的服务器在冒充真正的服务器。
公钥身份认证#
客户端生成一对公钥和私钥,并将自己的公钥复制到服务器上。客户端请求登录的时候,服务器会随机生成一个字符串并用客户端的公钥进行加密,客户端收到之后用自己的私钥解密后,再发送给服务器。服务器收到后进行比对,如果比对成功,就证明用户是可信的,直接允许登录,不再要求密码。从而避免了中间人攻击。具体过程如下:
基于密钥的安全验证简单的描述如图中所示。但在实际传输过程中所有的数据都是需要加密以保证数据传输安全,即同样会生成会话密钥,使用会话密钥对传输数据进行加密的过程。详细过程如下:
- 客户端发送登录请求,
ssh user@hostname
- 服务器接受请求,将服务器的公钥发送给客户端
- 服务器生成会话 ID (session id),设为 ,发送给客户端。
- 客户端生成会话密钥 (session key),设为 ,并计算
- 客户端将 用 进行加密,结果发送给服务器
- 服务器用服务器私钥进行解密,获得
- 服务器进行 的运算,获得
至此,服务器和客户端都知道了会话密钥 ,以后的传输数据都将被 加密。
- 客户端使用客户端私钥解密 得到
- 客户端计算 的 md5 值 , 为上一步得到的会话密钥
- 客户端将 发送给服务器
- 服务器计算 的 md5 值
- 服务器比较 和 ,两者相同则认证成功
至此,服务器和客户端认证通过,可以使用会话密钥进行加密和解密传输
- 客户端和服务器通过 进行会话数据安全传输
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
工具生成,通常会生成一对密钥(私钥 - 公钥),如下图所示。
用于服务器端的 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
工具生成,通常会生成一对密钥(私钥 - 公钥),如下图所示。
会话密钥 Session Key#
SSH 协议利用 Key Exchange 算法为每个会话或连接派生一个唯一的密钥,这个密钥被称为会话密钥 Session Key,常见的 Key Exchange 算法有 Diffie-Hellman 和 Elliptic-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
指定清除在配置文件中或在命令行上指定的所有local
、remote
和dynamic
端口发。GatewayPorts 2001
指定是否允许远程主机连接到本地的端口IdentitiesOnly no
指定 ssh 是否仅使用配置文件或命令行指定的私钥文件进行认证。值为yes
或no
,默认为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 实现 VPNTunnelDevice remote_tun
要打开 tun 的设备,local_tun 或 remote_tunUsePrivilegedPort 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
配置文件的关系#
配置详解#
- 关于 SSH Server 的整体设定,包含使用的 port 啦,以及使用的密码演算方式
Port 22
SSH 默认使用 22 这个 portProtoco- 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
是否可以使用压缩指令
- 说明主机的 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 的长度
- 关于登录文件的讯息数据放置与 daemon 的名称
SyslogFacility AUTH
当有人使用 SSH 登入系统的时候,SSH 会记录信息在 daemon name 下,默认是以 AUTH 来设定的,即/var/log/secure
里面,其它可用的 daemon name 为:DAEMON,USER,AUTH,LOCAL0,LOCAL1,LOCAL2,LOCAL3,LOCAL4,LOCAL5,LogLeve- INFO
登录记录的等级
- 登入设定部分
PermitRootLogin no
是否允许 root 登入。默认是允许的,但是建议设定成 noUserLogin no
在 SSH 底下本来就不接受 login 这个程序的登入StrictModes yes
使用者的 host key 改变之后,Server 就不接受新的 SSH 连接RSAAuthentication yes
是否完全使用 RSA 认证,仅针对 SSH v1PubkeyAuthentication yes
是否允许 Public Key 只针对 SSH v2AuthorizedKeysFile .ssh/authorized_keys
密钥身份认证的密钥路径
- 认证部分
RhostsAuthentication no
是否使用.rhosts
,因为不安全了,所以通常禁用IgnoreRhosts yes
是否取消使用~/.ssh/.rhosts
RhostsRSAAuthentication no
是否使用/etc/hosts.equiv
中的 rhosts 配合 RSA 演算方式来进行认证,只针对 SSH v1HostbasedAuthentication no
这个项目与上面的项目类似,只针对 SSH v2IgnoreUserKnownHosts no
是否忽略/home/.ssh/known_hosts
中记录的主机内容PasswordAuthentication yes
是否开启密码验证PermitEmptyPasswords no
是否允许以空的密码登入ChallengeResponseAuthentication yes
挑战任何的密码认证,任何 login.conf 规定的认证方式,均可适用!PAMAuthenticationViaKbdInt yes
是否启用其它的 PAM 模块!启用会导致 PasswordAuthentication 设定失效
- 与 Kerberos 有关的参数设定
KerberosAuthentication no
KerberosOrLocalPasswd yes
KerberosTicketCleanup yes
KerberosTgtPassing no
- 底下是有关在 X-Window 底下使用的相关设定
X11Forwarding yes
X11DisplayOffset 10
X11UseLocalhost yes
- 登入后的项目
PrintMotd no
登入后是否显示出一些信息,例如上次登入的时间、地点等等,默认是 yesPrintLastLog yes
显示上次登入的信息,默认是 yesKeepAlive yes
是否开启 keepaliveUsePrivilegeSeparation yes
使用者的权限设定项目MaxStartups 10
同时允许尚未登入的联机会话数量(连上 SSH 但是尚未输入密码时,即联机会话)
- 关于拒绝连接的设定项目
DenyUsers test
设定拒绝登录的用户名称DenyGroups test
设定拒绝登录的用户群组
- 关于 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 组件:
- 打开 “设置”,选择 “应用”>“应用和功能”,然后选择 “可选功能” 。
- 扫描列表,查看是否已安装 OpenSSH 。 如果未安装,请在页面顶部选择 “添加功能”,然后:
- 查找 “OpenSSH 客户端”,再单击 “安装”
- 查找 “OpenSSH 服务器”,再单击 “安装” 设置完成后,回到 “应用”>“应用和功能” 和 “可选功能”,你应会看到已列出 OpenSSH 。
分步教程参考《Windows - 安装 SSH 服务器》
对于 Window 10(版本 1809 以下)以及 Windows 7 手动安装 OpenSSH
- 下载对用系统版本的安装文件;GitHub 下载连接
- 将下载好的安装
.zip
文件解压; - 将解药好的文件夹整体复制到
C:/Program Files/
路径下,当然你可以放到你电脑上的任何你喜欢的路径下; - 在计算机(windows7) 或此电脑(windows10),右键 --> 属性 --> 高级系统设置 --> 环境变量 -- 系统变量,在此框里面找到
Path
进行编辑;
- windows7 系统编辑时候是以文本形式,所以就需要在最后先添加 “;” 英文分号,再把你安装路径
C:\Program Files\OpenSSH-Win64
粘贴进去;windows 10 系统添加比较方便,进到 Path 里面,点击新建直接粘贴进去;
详细教程请参考《Windows 安装 OpenSSH 支持 SSH》
在 Windows 上验证安装,打开cmd
或者powershell
$ ssh -V
OpenSSH_for_Windows_8.1p1, LibreSSL 3.0.2
设置 SSH 服务开机自启动
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 2048
,RSA
就是密钥算法;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 中添加的新算法,仅少量的客户端支持。
- 根据数学特性,这四种类型又可以分为两大类,dsa/rsa 是一类,ecdsa/ed25519 是一类,后者算法更先进。
- dsa 因为安全问题,已不再使用了。
- ecdsa 因为政治原因和技术原因,也不推荐使用。
- rsa 是目前兼容性最好的,应用最广泛的 key 类型,在用 ssh-keygen 工具生成 key 的时候,默认使用的也是这种类型。不过在生成 key 时,如果指定的 key size 太小的话,也是有安全问题的,推荐 key size 是 3072 或更大。
- 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 客户端与服务器端
简单配置服务器端#
- 为你要登录的用户 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
或其他后缀)。
- 将客户端生成的公钥(授权密钥)
~/.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
#
-
开启
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(默认值) -
将密钥添加到
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 通过对每个私钥执行签名和验证操作来测试与指定的私钥是否可用 -d 从 agent
中删除密钥-D 从 agent
中删除全部密钥-x 使用密码锁定 agent
,即暂停agent
管理密钥-X 使用密码解锁 agent
-q 操作成功后保持静默 -h 添加密钥时只用于特定主机或特定目标 -H 指定一个 hosts 文件用于此密钥在身份认证时查找主机密钥。可以多次指定多个 hosts 文件,用 ,
隔开
其他设置#
简化登录#
已经配置了免密码登录(公钥身份认证),但是如果你的用户名很复杂(例如用户名是邮箱地址等),或者不想及服务器的 IP 地址,那么可以更改配置文件来简化流程。
找到配置文件的路径:
- Linux
~/.ssh/config
- Windows
C:\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 基本用法:
-
从本地复制到远程主机
- 指定远程目录,复制完成后文件名称不变
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 个参数调换顺序即可
scp remote_username@remote_ip:remote_file local_file scp -r remote_username@remote_ip:remote_folder local_folder
-
指定端口号
-P
使用大写
P
#scp命令使用端口号4588 scp -P 4588 remote_username@remote_ip:remote_folder
-
免认证
配置 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 协议原理简介#
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 上的服务。
参考#
- 《使用 OpenSSH 管理 Windows》🔗
- 《SSH 协议基本原理及 wireshark 抓包分析》🔗
- 《SSH 技术白皮书》🔗
- SSH 学院🔗
- 《SSH 协议解析及 wireshark 抓包分析》🔗
- 《ssh 两种认证方式的原理介绍》🔗
- 《图解 SSH 原理》🔗
- 《windows 无法使用 ssh-copy-id 解决办法》🔗
- 《RSA,DSA,ECDSA,EdDSA 和 Ed25519 的区别》🔗
- 《ssh 使用的 RSA,DSA 和 ECDSA 密钥之间有什么区别?》🔗
- 《SCP 和 SFTP 相同点和区别》🔗
- 《Windows 安装 SSH 服务器》🔗
- 《Windows 安装 OpenSSH 支持 SSH》🔗
- 《配置 SSH 免密码登录(Public Key)》🔗
- 《OpenSSH 手册》🔗
- 《ssh 代理转发介绍以及应用场景》🔗
- 《Linux 学习笔记 5 - ssh-agent 详解》🔗