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位。
密钥文件
密钥主要是用来签名验证自身的身份,因此对于一个固定PC/服务器的一个用户,通常只需要在本地维护一个密钥对,
用户必须保证安全地保存密钥,并且需要将公钥手动传递给希望远程登陆的服务器,见下文。
密钥通常存放在~/.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
ssh-keygen -t rsa
-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
参数可以指定生成的私钥文件 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_keys
config
known_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:xxx.xxx.xxx.xxx:22 user@remotehost_B
在建立了ssh隧道之后,主机A想要登陆到主机C,访问localhost:22022
即可(在A上执行命令)
1
ssh -p 22022 user@localhost
远程转发
远程转发指的是在远程 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:xxx.xxx.xxx.xxx: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代理。
补充
ssh端口转发除了上面最基本的三个主机之间的操作,还可以加上更多的跳板服务器,此时需要在不同的主机上执行转发命令。
如果需要经常进行端口转发,还可以把转发写入配置文件中,这里不作讨论。
代理转发
-W
选项要求openssh版本高于7.3,更低版本可以使用netcat
工具进行替代。
这部分内容不作详细讨论,只是提供一个典型的例子:内网中有主机A和主机B,主机A无法可以连通github,但是主机B可以,那么我们可以在主机A中添加如下配置
1
2
3
4
5
6
7
8Host B
...
Host github.com
User git
HostName github.com
ProxyCommand ssh -q -W %h:%p B
ForwardAgent yes
主机A就会通过主机B来连接github,注意此时我们仍然使用的是主机A的密钥对,需要保证公钥已经被添加到github中,密钥不需要存储在跳板机B中。
Github
除了远程登录服务器,使用Github也是配置ssh密钥的常见需求,直接在本地生成密钥对,然后把公钥上传到Github即可。
可以用下面的语句测试ssh配置是否正确 1
ssh -T git@github.com
在大部分情况下直连Github是可以的,但是偶尔会出现连接超时,无法推送和拉取Github仓库,有很多种解决办法,原理各不相同,而且都无法保证奏效。
可以尝试换一个网络,手机热点通常比校园网更好使;
对于使用http/https的远程仓库,可以用下面的命令让其走代理,注意修改代理的端口号(加上
--global
全局生效)1
2git config http.proxy http://127.0.0.1:7892
git config https.proxy https://127.0.0.1:7892可以参考下面的socks5代理配置(适合Windows,对于Linux代理命令略有不同),这里注意修改为clash所设置的端口(默认7890,我改成了7892);
1
2
3Host github.com
User git
ProxyCommand connect -S 127.0.0.1:7892 %h %p可以使用
ssh.github.com
代替github.com
,这会把ssh连接从22改到443,某些情况下会好很多(参考官方文档)。建议在.ssh/config
中直接覆盖修改,而不是修改git远程仓库的URL;1
2
3
4Host github.com
User git
Port 443
HostName ssh.github.com
将代理转发和ssh.github.com结合可以得到如下的方案 1
2
3
4
5
6
7
8Host B
...
Host github.com
User git
HostName ssh.github.com
ProxyCommand ssh -q -W %h:%p B
ForwardAgent yes
各种方案可以参考一文让你了解如何为 Git 设置代理。