Linux ssh 笔记
详细记录一下关于 ssh 的内容,这部分内容比较繁杂。
基本使用(1)
ssh 最基本的用途就是登录远程服务器 1
ssh user@hostname
其中:
user是登录用户名hostname是主机名,它可以是域名,也可以是某个具体的 IP 地址或局域网内部的主机名。
可以缺省用户名,此时将使用本地用户名作为远程服务器的登录用户名。
1
ssh hostname
用户名也可以通过 -l
参数指定,这样用户名和主机名就不用写在一起了,在脚本中可能更方便
1
ssh -l username hostname
ssh 会默认连接远程服务器的 22 端口,使用 -p
参数也可以指定其他端口(同时也要修改远程服务器的监听端口)
1
ssh -p 8821 foo.com
ssh 在连接到远程服务器后会进行验证:如果第一次通过 ssh
连接某一台服务器,
命令行会显示一段文字,表示不认识这台机器,提醒用户确认是否需要连接
1
2
3The authenticity of host 'foo.com (192.168.121.111)' can't be established.
ECDSA key fingerprint is SHA256:Vybt22mVXuNuB5unE++yowF7lgA/9/2bLSiO3qmYWBY.
Are you sure you want to continue connecting (yes/no)?
这段文字告诉用户,foo.com
这台服务器的指纹是陌生的,用户需要确认是否要继续连接(输入 yes 或
no)。
所谓 “服务器指纹” 指的就是 ssh
服务器提供的公钥的哈希值,利用公钥的特性可以识别和确认服务器,下面的命令可以查看某个公钥所对应的指纹
1
2ssh-keygen -l -f /etc/ssh/ssh_host_ecdsa_key.pub
256 da:24:43:0b:2e:c1:3f:a1:84:13:92:01:52:b4:84:ff (ECDSA)
ssh 会自动将曾经连接过的所有服务器公钥的指纹,储存在
~/.ssh/known_hosts 文件中,具体的内容格式对 Windows 和
Linux 不太一样。
每次连接服务器时,通过该文件判断是否为陌生主机(陌生公钥),对于陌生主机需要手动确认,对于已经存储在
~/.ssh/known_hosts 文件中的则不再需要确认。
我们可以使用下面的命令检查指定的主机名是否在 known_hosts
中,或者将指定主机名从 known_hosts 中移除 1
2
3
4
5# find
ssh-keygen -F example.com
# remove
ssh-keygen -R example.com
ssh 在验证了服务器指纹之后会要求用户输入所要登录账户的密码,用户输入并验证密码正确以后,就可以登录远程服务器的 Shell 了。 (如果采用下面的密钥登陆,则无需输入密码)
有时我们只需要临时登录并执行一条简单命令,可以把命令直接加在后面,在登录之后会自动执行这条命令并输出到本地,然后自动退出
ssh 登录,例如 1
ssh user@hostname cat /etc/hosts
密钥
非对称加密算法
ssh 支持很多种非对称加密算法,用于登陆时的认证签名:
- RSA 算法,基于大数分解,兼容性最好,所有 ssh 客户端都支持此算法。
- ECDSA 算法:基于椭圆曲线,需要在新的场景中使用更安全的密钥时,可以选择此类型。
- ED25519 算法:基于 Edwards 曲线(也属于椭圆曲线),提供极高的安全性和性能,兼容性相对最差。
除此之外,还有两种已经被淘汰的算法:ssh 协议版本1的 RSA 算法(目前使用的是版本2的 RSA 算法)和 DSA 算法(基于离散对数),不建议在新场景中使用。
关于密钥的位数:
- RSA 算法:必须加大密钥位数来提升安全性,建议密钥位数至少为 2048 位,推荐使用 3072 位或 4096 位以获得更高的安全性。
- ECDSA 算法:只支持三种密钥大小:256,384 和 521 位,即使最低的 256 位也已经非常安全,384 位和 521 位提供额外的安全冗余。
- ED25519 算法:密钥大小固定为 256 位,安全性在 RSA 2048 与 RSA 4096 之间,且性能数十倍于 RSA 算法。
有的比较激进的组织出于安全性的原因,已经考虑禁止使用RSA密钥,建议使用后两种算法,并且对于 ECDSA 算法建议使用最长的 512 位。
密钥文件
密钥主要是用来签名验证自身的身份,因此对于一个固定机器上的一个用户,通常只需要在本地维护一个密钥对,
用户必须保证安全地保存密钥,并且需要将公钥手动传递给希望远程登陆的服务器,见下文。
密钥通常存放在 ~/.ssh 目录下,下面是这些文件的默认名称
id_rsa,id_rsa.pub:用于 SSH 协议版本2 的 RSA 私钥和公钥。id_ecdsa,id_ecdsa.pub:ECDSA 私钥和公钥。id_ed25519,id_ed25519.pub:ED25519 私钥和公钥。identity,identity.pub:用于 SSH 协议版本1 的 RSA 私钥和公钥。(通常没有,除非在很老的机器中)
在 Linux 系统中,ssh 要求用户的私钥文件不能被其它用户直接访问到,否则会拒绝使用这个不安全的私钥,可以使用
chmod命令将私钥文件的权限设置为 600 或 400,对于公钥文件则没什么要求,例如设置为 644 即可。
私钥文件和公钥文件都是文本文件,私钥例如 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38-----BEGIN OPENSSH PRIVATE KEY-----
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
yf/PzW634X+YF3AAAACWxpc2h1QFRYSgE=
-----END OPENSSH PRIVATE KEY-----
RSA 算法需要足够长的私钥来保证安全性,如果采用新的算法(ECDSA 或 ED25519)则私钥长度可以短很多。
公钥例如 1
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCmP1rbqoMBBO9rBNSfRYZyyRUlWeF1pldu3bW8MMfXf/oR78CEN4MT643ZV994qlukZJHjja3cE9X23mUley78DMUaSCIDF+KuBlZYNv1Iaok6MMbUMNfXXESms5bjAT76kpx35IGvbSyOnpgmXMeMcxGbRtgbe448mZCESh8/+mUciznqZiHjhC8oZWJOrvJyx/TYR/wfoNz1MxfafBf0HEUSShxU6HjfQHlt5+rA++mzjOtlTEcqxWIXKDvDy3iVn885kwpUQazQ8D2rJZBmycggRI4TGw6iZYyp5YZ9akXnW2qmT71GNxI6Xt0SUOQIlHHD/9U1yZhebAbkCaPzHbiG1XII78PVxOUcSyo7cp5fVmINwgjEuq0oCbwSdfGPISl32NKeBzGDSLz/qwb9YQXGZRv5FDWP7TZkO78r8+RGKDDWHP8F7XuE3sPrObkCTkMim1jxWdIdXBs/JbG/MJQaplseUKGTKlmeJ5x9SvsmlaE09i2ST7dIAnlrtK0= your_email@domain.com
公钥内容只有一行,比私钥长度小很多,在公钥文件的开头会表明当前算法的类型,在文件末尾的空格之后会有一个注释,标记公钥所对应的用户名和主机名,这个注释并不是密钥的一部分,只是便于区分不同的公钥,我们可以直接修改注释,这不会对密钥对产生影响。
密钥生成
ssh 提供的配套工具 ssh-keygen 可以用于生成密钥(默认使用 RSA
算法),当然我们也可以通过其它工具生成密钥对,因为算法都是公开的
1
ssh-keygen
ssh-keygen 需要我们确认或修改几个信息:
- 保存的路径和文件名,使用默认的路径和文件名即可,还可以通过
-f选项指定,见下文 - 密钥对的保护密码(passphrase),客户端在每次使用这个密钥对时需要用户输入保护密码,通常使用空密码即可,还可以使用
-N选项指定保护密码,见下文
最后 ssh-keygen
会生成一对密钥对,将其存储到指定位置,然后显示公钥的指纹和一个基于公钥生成的图像,
用图像来判断比使用字符串形式的指纹对人类更加友好 1
2
3
4
5
6
7
8
9
10
11
12
13
14The key fingerprint is:
SHA256:MaA3rGf/h3Jh5jVehAw6QerUG0TMOTJN/n93P2zwMXs xxx@yyy
The key's randomart image is:
+--[ED25519 256]--+
| .B=. |
| oo*B . |
| . *o*+ o . |
| = .o* o . |
| . + S.. . |
| o . +.o..o |
| .+ =.o= *|
| ..+ o. BE|
| o.. . +|
+----[SHA256]-----+
ssh-keygen 支持很多选项,下面介绍几个最常用的选项。
-t 选项可以指定加密算法,默认是RSA算法
1
2ssh-keygen -t rsa
ssh-keygen -t ed25519
对于位数可变的算法,-b 选项可以指定密钥的二进制位数
1
ssh-keygen -t rsa -b 4096
对于位数可变的算法,我们必须使用合法的位数,RSA算法默认采用 2048 位,ECDSA 算法默认采用 256 位,位数都是足够的;对于位数固定的 ED25519 算法,这个选项会被直接忽略。
-C 选项可以为公钥文件指定注释,格式为
username@host,默认是当前用户名和当前主机名
1
ssh-keygen -C "your_email@domain.com"
-f
参数可以指定生成的私钥文件(否则使用默认名称,并存放在
~/.ssh/ 目录下) 1
ssh-keygen -f mykey
这个命令会在当前目录下生成私钥文件 mykey 和公钥文件
mykey.pub。
-N 参数可以指定私钥的保护密码(passphrase)
1
2
3ssh-keygen -N secretword
# empty
ssh-keygen -N ''
使用下面的命令可以利用现有的私钥生成对应的公钥 1
2ssh-keygen -y -f key_file_name # 输出到标准输出流
ssh-keygen -y -f key_file_name > key_file_name.pub
完整的生成密钥对的命令如下 1
ssh-keygen -t rsa -C "your_email@domain.com" -f key_file_name -N ''
基本使用(2)
密码登陆过于繁琐且不够安全,更建议的做法是使用密钥登陆,大致流程如下:
- 预备步骤,客户端通过 ssh-keygen 生成自己的公钥和私钥,手动将客户端的公钥放入远程服务器中的指定位置。
- 第一步,客户端向服务器发起 ssh 登录的请求。
- 第二步,服务器收到用户 ssh 登录的请求,发送一些随机数据给用户,要求用户使用私钥加密以证明自己的身份。
- 第三步,客户端收到服务器发来的数据,使用私钥对数据进行加密,然后再发还给服务器。(使用私钥加密数据的过程通常被称为签名)
- 第四步,服务器收到客户端发来的加密签名后,使用对应的公钥解密检查,如果数据一致就允许用户登录。
密钥对的生成在上面已经介绍,下面关注将公钥上传到服务器中。
用户公钥保存在服务器的 ~/.ssh/authorized_keys
文件中,把公钥添加到这个文件之中就是把公钥上传到服务器了。
authorized_keys
是纯文本文件,其中可以包括多个公钥,每个公钥占据一行,把最新的公钥粘贴到文件尾部即可。
如果 authorized_keys 文件不存在,也可以直接手动创建。
和私钥文件类似,ssh 对
authorized_keys文件的权限也有要求,建议设置为 644,权限不对可能导致 ssh 使用失败。
用户可以使用密码登陆到远程服务器,然后手动编辑该文件,把公钥粘贴进去,也可以直接在本机计算机上,执行下面的命令
1
cat ~/.ssh/id_rsa.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
注意将这里的文件替换为需要上传的密钥文件,需要确保服务器上的
authorized_keys 没有格式错误,并且文件权限正确。
在配置了密钥对之后,我们就可以使用 -i
选项指定密钥而非使用密码进行远程登陆 1
ssh -i /path/to/private_key user@hostname
如果缺省 -i 选项,ssh
客户端会依次尝试使用下面的几个私钥文件(如果存在的话)
~/.ssh/id_rsa~/.ssh/id_dsa~/.ssh/id_ecdsa~/.ssh/id_ed25519
我们还可以使用 ~/.ssh/config
文件进行更详细的配置,见下文。
配置
客户端配置
ssh 客户端通常需要关注如下两个配置文件:
~/.ssh/known_hosts:记录登陆过的服务器的公钥指纹,还有一个known_hosts.old是在主机指纹发生更改时,客户端进行的自动备份;~/.ssh/config:用户级配置文件,与之相对的是全局配置文件/etc/ssh/ssh_config,用户级的优先级更高。
config 配置文件由一系列 Host
块组成,每个块包含一组针对特定主机或一组主机的配置选项。
配置冲突时,后面的块优先级比前面的更高,通常会先将通用的放在前面,具体的放在后面,例如
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24# 通配符配置
Host *
ServerAliveInterval 60
Host *.example.com
User commonuser
Port 2222
# 具体主机配置,优先级更高
Host myserver1.example.com
User user1
Port 2200
Host myserver2
HostName myserver2.example.com
User user2
Port 2222
Host myserver3
HostName myserver3.example.com
User user3
Port 2200
IdentityFile ~/.ssh/id_rsa3
解释一下这里的选项:
Host <pattern>:指定主机模式,可以是 ip 或具体主机名,也可以包含通配符HostName:实际要连接的主机名User:登录用户名Port:端口号(默认是22)。IdentityFile:用于身份验证的私钥文件路径,如果缺省则会依次尝试id_rsa,id_dsa,id_ecdsa和id_ed25519这些默认文件。ServerAliveInterval:发送到服务器的间隔秒数,以保持连接活跃ServerAliveCountMax:在放弃连接之前,服务器没有响应的最大次数
服务端配置
ssh 服务端通常需要关注如下两个配置文件:
~/.ssh/authorized_keys:记录允许从远程登陆的用户公钥;/etc/ssh/sshd_config:ssh 服务端(sshd 服务)的全局配置文件。
修改服务器上的/etc/ssh/sshd_config可以控制用户的 ssh
登陆行为,例如 1
2
3
4
5
6
7
8
9
10
11# 设置ssh的端口(还需要修改防火墙等)
# 默认:22
Port 2222
# 不允许使用密码登陆
# 默认:yes
PasswordAuthentication no
# 不允许root用户从远程登陆(建议先用普通用户登陆,然后切换为root用户)
# 默认:不允许root用户远程密码登陆 prohibit-password
PermitRootLogin no
修改需要重启 sshd 服务才能生效。
除了配置文件,ssh 服务端在 /etc/ssh/
目录中还存储了所有的服务端密钥对,例如
/etc/ssh/ssh_host_ecdsa_key,
这些服务端密钥对被用于生成服务器指纹,重装 ssh
服务端可能会导致这些密钥对重新生成,之前的指纹记录就全部失效,我们必须在重装之前备份这些密钥。
git 是一个特殊的用户,我们需要避免使用 git 用户登陆到远程服务器的
shell,通常的做法是修改 /etc/passwd 文件中 git
所在的行,使用定制的 git-shell 替代默认的 bash
1
git:x:1003:1003:,,,:/home/git:/usr/bin/git-shell
当然我们也可以直接在 /etc/ssh/sshd_config
中通过白名单的形式禁止 git 用户的远程登陆, 但这会导致我们无法通过 ssh
访问在服务器中的 git 仓库。
文件权限小结
整理一下关于 Linux 系统中 .ssh/ 目录下的权限要求:
- 私钥:自动生成的私钥为 600,改成 400 也可以,如果对其它用户可读就会报错
- 其它所有的文件都建议使用 644 权限,包括:
- 公钥
authorized_keysconfigknown_hosts
进阶使用
端口常识
下面是不同端口号段的含义:
- 0-1023: 知名端口,预留给常见的服务和协议。
- 1024-49151: 注册端口,一般分配给用户进程或特定服务。
- 49152-65535: 动态端口或私有端口,通常用于临时目的,如客户端程序向服务器发起连接。
知名端口例如:
- HTTP:80
- HTTPS:443
- FTP:21
- SSH:22
- DNS:53
可以使用下面的命令查看当前是否监听了某个端口 1
2# Windows
netstat -ano | findstr :22022
如果想要关闭监听,可以在任务管理器搜索进程号,然后结束任务即可。如果要终止 ssh 对端口的监听,也可以直接搜索 ssh 任务,然后关闭。
端口转发
ssh 除了登录服务器,还有一大用途:作为加密通信的中介,充当服务器之间的通信加密跳板。这个功能称为端口转发(port forwarding),又称 ssh 隧道(tunnel)。端口转发有两个主要目的:
- 将不加密的数据放在 ssh 安全连接里面传输,使得原本不安全的网络服务增加安全性。
- 作为数据通信的加密跳板,绕过网络防火墙。
ssh 提供三种形式的端口转发:
- 本地转发(
-L选项) - 远程转发(
-R选项) - 动态转发(
-D选项)
在下文中还可以加上:
-N选项,它表示这个 ssh 连接只用于端口转发,不会登录远程 Shell 并执行远程命令,只能充当隧道。-f选项,它表示 ssh 连接在后台进行。
这些选项的位置建议放在最后,至少要在转发的选项和参数之后。实践发现:
- 如果两个选项都不加,那么端口转发会打开一个远程 shell,并且 shell 退出后隧道自动关闭;
- 如果加上
-N选项,那么不会打开远程 shell,但是在当前 shell 被关闭后,隧道也会自动关闭; - 如果加上
-N -f选项,那么不会打开远程 shell,并且在当前 shell 退出后,隧道仍然存在,需要找到后台进程并手动关闭; - 只加上
-f选项会报错。
在下面的各种转发命令中都省略了关于这些选项的讨论。
如果需要经常进行端口转发,可以把转发直接写入配置文件中,这里不作讨论。
本地转发
本地转发是在本地计算机建立的转发规则,具体含义为: 创建一个本地端口,将发往该端口的所有通信都通过 ssh 服务器,转发到指定的远程服务器的端口。 这种情况下,ssh 服务器只是一个作为跳板的中介,用于连接本地计算机无法直接连接的远程服务器。
1 | 场景: |
本地转发的命令格式为(在 A 上执行命令) 1
ssh -L A-tunnel-port:C-host:C-port B-host
其中:
A-tunnel-port:主机 A 上的端口,作为隧道入口C-host:主机 C,可以是 C 的内网 ip,只要 B 可以访问即可C-port:主机 C 的目标端口,如果需要使用 ssh 访问主机 C,那么最好使用 22 号端口B-host:跳板机 B
例如(在 A 上执行命令) 1
ssh -L 22022:C-host:22 user@B-host
在建立了 ssh 隧道之后,主机 A 想要登陆到主机 C,访问
localhost:22022 即可(在 A 上执行命令) 1
ssh -p 22022 user@localhost
本地转发的一个更常见的应用情景是:远程服务器 C-host
的某个服务在监听端口 C-port, 本地主机 A-host
可以通过 ssh 连接到
C-host,但是由于防火墙等原因无法直接访问端口
C-port,此时可以使用本地转发功能(B-host=C-host),在本地的
A-tunnel-port 和远程服务器的 C-port
之间建立隧道。
1 | ssh -N -L A-tunnel-port:localhost:C-port user@C-host |
这里 -N 是不登陆,仅建立隧道。
远程转发
远程转发指的是在远程 ssh 服务器建立的转发规则,含义跟本地转发正好反过来:建立本地计算机到远程 ssh 服务器的隧道以后,本地转发是通过本地计算机访问远程 ssh 服务器,而远程转发则是通过远程 ssh 服务器访问本地计算机。
1 | 场景: |
远程转发的命令格式为(在跳板 B 上执行命令) 1
ssh -R A-tunnel-port:C-host:C-port A-host
其中:
A-tunnel-port:主机 A 上的端口,作为隧道入口C-host:主机 C,可以是 C 的内网 ip,只要 B 可以访问即可C-port:主机 C 的目标端口,如果需要 ssh 访问主机 C,那么使用 22 号端口A-host:主机 A
例如(在跳板 B 上执行命令) 1
ssh -R 22022:C-host:22 user@A-host
在建立了 ssh 隧道之后,主机 A 想要登陆到主机 C,访问
localhost:22022 即可(在 A 上执行命令) 1
ssh -p 22022 user@localhost
动态转发
动态转发指的是本机与 ssh 服务器之间创建了一个加密连接,本机内部针对某个端口的通信都通过这个加密连接转发,由 ssh 服务器代劳。 动态转发只是把本地端口绑定到 ssh 服务器,至于 ssh 服务器要去访问哪一个网站,完全取决于通信的要求,所以叫做动态转发。
一个常见的使用场景是:对所有外部网站的访问都转发到 ssh 服务器,实际上是用 ssh 服务器去访问。
这里有一个问题:之前使用固定的端口转发时,应用的访问请求都是明确指向被转发的端口 X,但现在应用的访问请求必须指向目标,以指定动态端口转发的目标,此时如何让数据全部从端口 X 进入 ssh 隧道?我们必须在系统或应用(浏览器等)中手动设置一个使用 SOCKS5 协议、服务器为 localhost、端口为X的代理,利用代理使这些网络请求全部走端口 X。
应用的网络请求从端口 X 进入 ssh 隧道,抵达 ssh 服务器后将其中的目标信息解析出来,ssh 服务器访问目标后再将结果通过隧道返回。
动态转发的命令格式为 1
ssh -D local-port tunnel-host
例如使用本地的2121端口 1
ssh -D 2121 tunnel-host
这里会自动登陆到 tunnel-host,但是无所谓,也可以使用 -N
不登陆,此时会处于阻塞状态。(关闭这个会话则转发随之停止)
curl 进行网络访问时需要加上 -x 选项设置 SOCKS5 代理
1
curl -x socks5://localhost:2121 www.baidu.com
注意 wget 不支持 socks5 代理,只支持 http 代理和 https 代理。
代理转发
-W选项要求 openssh 版本高于 7.3,更低版本可以使用netcat工具进行替代。
这部分内容不作详细讨论,只是提供一个典型的例子:内网中有主机 A 和主机
B,主机 A 无法通过 ssh 连通 example.com,但是主机 B
可以,那么我们可以在主机 A 中添加如下配置 1
2
3
4
5
6
7
8Host B
...
Host example.com
User git
HostName example.com
ProxyCommand ssh -q -W %h:%p B
ForwardAgent yes
主机 A 就会通过主机 B 来连接
example.com,注意此时我们仍然使用的是主机 A
的密钥对,需要保证公钥已经被添加到 example.com
中,密钥不需要存储在跳板机 B 中。 (测试发现
ForwardAgent yes 删掉也可以正常工作)
跳板选项
-J选项要求 openssh 版本高于 7.3。
-J
选项可以简化基于跳板机登陆的步骤,更加简单易读,在本地主机 A
上执行如下命令 1
ssh -J userB@B userC@C
其中 B 是跳板机,C 是目标主机。
原本的端口转发命令也可以直接加上跳板机,例如 1
ssh -J userB@B -N -L 8989:localhost:8888 userC@C
