1. SSH 应对中间人攻击的方法#

SSH 采用了公钥加密, 过程如下:

(1)Remote Host 收到用户的登录请求, 把自己的公钥发给用户

(2)用户使用这个公钥, 将登录密码加密后, 发送过去

(3)Remote Host 用自己的私钥, 解密信息, 验证密码是否正确

这个过程存在一个漏洞:如果有人截获了用户的登录请求,然后冒充 Remote Host,将伪造的公钥发给用户,那么用户很难辨别真伪。这就是 Man-in-the-middle attack, 应对方法有两种:

  • 利用公钥指纹人工进行对比验证,
  • 上传公钥实现免密登录

接下来我们一一介绍这两种方法,

2. 利用公钥指纹人工进行对比验证#

看来面的例子, 在Mac上通过ssh连接远程的服务器, 第一次连接的时候会问下面提示:

ssh root@144.202.16.29        
The authenticity of host '144.202.16.29 (144.202.16.29)' can't be established.
ED25519 key fingerprint is SHA256:sa5vDYS0yhdMRXO6CgMrp9AcQoVQRiDw6TnzTKesnzQ.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
....

这是 ssh 在提醒它无法确认 remost host 是不是就是你要连接的那个主机, 因为可能会发生中间人攻击嘛, 但知道它的公钥指纹是sa5vDYS0..., 问我们还要继续连接吗 (注意单词 establish 在这是 “认证确认” 的意思),

那我们怎么知道远程主机的公钥指纹应该是多少?当然是去你的服务器上查看公钥指纹:

[root@vultr ssh]# ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
256 SHA256:sa5vDYS0yhdMRXO6CgMrp9AcQoVQRiDw6TnzTKesnzQ root@vultr.guest (ED25519)

注意如果你的服务器使用的是其他hash function生成的公钥指纹, 那你就要查看其他文件了:

ssh-keygen -E md5 -lf /etc/ssh/ssh_host_ed25519_key.pub

可以发现输出内容与上面 ssh 警告的指纹相同, 所以我们要来接的这个是我们的真正主机,

可能有人会说, 那我们买的服务器物理主机在谷歌阿里, 怎么去直接验证? 你可以在你购买VPS的网站上连接自己服务器保证你连接的一定是你的主机, 但我们只是测试, 所以你直接忽略 ssh 的提示警告, 输入yes, 连上服务器后去验证一下就好了, 因为肯定不会有中间人闲的蛋疼来攻击我们的连接吧? 几块钱一个月的服务器, 谁来攻击你,

有人可能又会疑问, 那我们也可以直接去远程主机查看他的公钥啊, 为啥还要用个hash函数来生成它的指纹, 再去比对, 不是多此一举吗? 首先你没发现公钥的指纹很短吗? 我们去远程主机验证一般是用肉眼来比对吧, 那公钥那么长, 几百个字符, 很容易比对错, 而公钥指纹的主要目的就在于它很短, 方便我们比对,

最后关于 ssh 输出的信息, 还有其它想说的, 根据输出:

ssh root@144.202.16.29        
The authenticity of host '144.202.16.29 (144.202.16.29)' can't be established.
ED25519 key fingerprint is SHA256:sa5vDYS0yhdMRXO6CgMrp9AcQoVQRiDw6TnzTKesnzQ.
...

该 remote host 上的 ssh 使用的公私钥是由 ED25519 算法生成的, ED25519 是非对称加密算法, 常见的非对称加密算法还有 RSA, 所以 RSA 和 ED25519 是并列的: Today, the RSA is the most widely used public-key algorithm for SSH key. But compared to Ed25519, it’s slower and even considered not safe if it’s generated with the key smaller than 2048-bit length. EdDSA is a digital signature scheme, Ed25519 is the EdDSA signature scheme using SHA-512 (SHA-2) and Curve25519. –Wiki

另外, 该公钥指纹是由 SHA256 hash function 生成的, 另外常见的 hash function 还有md5,

2.1. 验证公私钥位置#

这个时候我们在电脑终端输入yes, 然后就会提示输入密码 (比如root用户对应的密码), 然后系统会提示如下:

Warning: Permanently added '144.202.16.29' (ED25519) to the list of known hosts.
root@144.202.16.29's password: 
Last login: Fri Apr  7 20:36:06 2023
[root@vultr ~]# ls

当远程主机的公钥被接受以后, 它会被保存在文件~/.ssh/known_hosts之中, 下次再连接这台主机, 系统就会认出它的公钥已经保存在本地了, 从而跳过警告部分, 直接提示输入密码, 我们来查看Mac上的输出:

ls ~/.ssh 
id_rsa          id_rsa.pub      known_hosts     known_hosts.old

cat ~/.ssh/known_hosts 
github.com ssh-ed25519 AAAAC3NzaC1lZDI1N...
github.com ecdsa-sha2-nistp256 AAAAE2VjZH....
github.com ssh-rsa AAAAB3NzaC1yc2EAAAADA....

144.202.16.29 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOpG35RMxOKeeLbTfdWlPgToThzrm00sRpMRQs+pdYig
144.202.16.29 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHP5xEl1122X1Vtc5LzqMp6vlvd4cHRD151ag61xXThvT7KM9vuUK23ol4LKoXMoivUH1SAcWandumVKG37zZfA=

再看看服务器上的输出,

[root@vultr ssh]# ls /etc/ssh
moduli            ssh_host_dsa_key.pub    ssh_host_ed25519_key.pub
ssh_config        ssh_host_ecdsa_key      ssh_host_rsa_key
sshd_config       ssh_host_ecdsa_key.pub  ssh_host_rsa_key.pub
ssh_host_dsa_key  ssh_host_ed25519_key

[root@vultr ssh]# cat ssh_host_ed25519_key.pub 
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOpG35RMxOKeeLbTfdWlPgToThzrm00sRpMRQs+pdYig root@vultr.guest

[root@vultr ssh]# cat ssh_host_ecdsa_key.pub 
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHP5xEl1122X1Vtc5LzqMp6vlvd4cHRD151ag61xXThvT7KM9vuUK23ol4LKoXMoivUH1SAcWandumVKG37zZfA= root@vultr.guest

这两个一个是公钥, 一个是公钥的指纹, 可以看出和上面Mac的存储的内容是一样, 然后上面在服务器 ls /etc/ssh 的输出, 有 ssh_host_rsa_key.pub, ssh_host_ecdsa_key.pub 这就是使用不同的算法产生的不同的key,

最后 Mac 上 ~/.ssh/known_hosts 的输出 github 那部分有 ssh-ed25519, ecdsa-sha2-nistp256, 这是什么呢?

For ssh-ed25519 and ecdsa-sha2-nistp256 which one is used for a given connection depends on the capabilities and preferences of the client, namely your ssh program. If you are using OpenSSH versions 6.5 to 8.1, then it prefers ecdsa then ed25519, and only 8.2 up prefers ed25519 first. Why does GitHub recommend ed25519 SSH key encryption scheme, but itself uses ECDSA? - Super User

  • ecdsa-sha2-nistp256: Specifies the ECDSA algorithm with 256-bit key strength
  • rsa: Specifies the public key algorithm rsa

3. Public Key Authentication (上传公钥实现免密登陆)#

3.1. 过程分析#

使用密码登录, 每次都必须输入密码, 非常麻烦, 好在SSH还提供了公钥登录, 可以省去输入密码的步骤, 具体验证过程如下:

  1. The client generates a public/private key pair, typically with RSA or ECC. The client keeps the private key secret and registers the public key with the SSH server.
  2. When the client connects to the server, the server authenticates the client by checking if it has the corresponding public key registered for that client.
  3. The server will send a challenge message to the client, requesting authentication.
  4. The client will take the challenge message and use its private key to generate a digital signature. This proves that the client has the correct private key without revealing the key itself.
  5. The client sends the digital signature back to the server as a response to the challenge.
  6. The server verifies the signature using the client’s registered public key. If the signature is validated, the server knows the client has proven possession of the corresponding private key and grants it access.

注意关于验证过程, 不同 ssh 版本可能会有不同的实现, 你可能会看到有人说远程主机用 用户的公钥进行解密验证, 其实公钥并不可以用来解密, 别人指的应该是公钥可以用来验证数字签名, 即这种情况下私钥加密其实应该是私钥签名。 私钥 “加密” 以后,谁用公钥都可以打开,就已经失去了加密的意义,所以它只能起到一个“签名”的效果,来达到-大家知道这条信息是我,而且只有我发出的。

记住公钥只能用来加密, 不可以用来解密, 不然就不叫公钥了, 所以是远程主机用 用户的公钥进行用户的验证数字签名, 总结公钥有俩功能:

  • 加密
  • 验证数字签名

3.2. 具体操作#

远程主机需要使用用户的公钥来验证用户的身份, 所以本地机器要生成公私钥:

# generate ssh keys
$ ssh-keygen

一路回车之后在~/.ssh/会新生成两个文件:id_rsa.pubid_rsa, 前者是你的公钥, 后者是你的私钥, 这时再输入下面的命令, 将公钥传送到远程主机host上面:

$ ssh-copy-id root@144.202.16.29

完成, 之后再登录就不需要输入密码了:

$ ssh root@144.202.16.29

其实你也可以直接编辑远程主机 ~/.ssh/authorized_keys 文件, 把你本地主机的公钥的内容添加进去就行了, ssh-copy-id root@144.202.16.29 做的就是这件事. 下面我们会验证.

4. authorized_keys file#

上面 ssh-copy-id root@144.202.16.29 执行后, 本机公钥存储在了远程主机~/.ssh/authorized_keys:

[root@vultr ~]# ls -a
.   .bash_history  .bash_profile  .cache  .pki  .tcshrc
..  .bash_logout   .bashrc        .cshrc  .ssh

[root@vultr ~]# cat .ssh/authorized_keys 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDvbHLCIxxUDDqktbqdrICPa+JDd3kEyowKpy9igugi7R+f/94UDBDJLmeu+K8wi90pjwq+mTM6bSPXBkjmYGibCPbUKk7RtrVx5FdR488PR7/ptMqQXJeQeMOIXvK2Lfnzay+rH5Fg/8z1+pd7cuHPq0bWm5LroGq+bYXVTIYgjKC5NDxPbQCY7zd4c0L+SvxlwqrJFvRBZKY41UBLywtuM8geluLWaGcbikX1K2hFVcZ7ETogG7eqdRBtbfx+JxhyRY1Od+snM88CSfuQkOgs4xQli3GrGttgY0f8BA65/pbixG9gAPkacEkexS997iuTP9BmwLmwWq1pw91c0yEQO1JnsbGHj/YfRhBV6s4FL8n5uVC0My64tisqA+8eZTeld8Zwem4XQGjoqwt2HYy1YXv0kOU8NyI0EGDz3fmqER3ex0cL+MqvWf/cnWQ6MRvGI3w/gL3+V8ueZv5qXpnY+ZH2UcrqEv7Xl74fkdqPYo53ySLQ9ZCiCitHgMjl3bk= shwezu@qq.com

在Mac上查看我自己的公钥, 是一样的:

# cat id_rsa.pub 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDvbHLCIxxUDDqktbqdrICPa+JDd3kEyowKpy9igugi7R+f/94UDBDJLmeu+K8wi90pjwq+mTM6bSPXBkjmYGibCPbUKk7RtrVx5FdR488PR7/ptMqQXJeQeMOIXvK2Lfnzay+rH5Fg/8z1+pd7cuHPq0bWm5LroGq+bYXVTIYgjKC5NDxPbQCY7zd4c0L+SvxlwqrJFvRBZKY41UBLywtuM8geluLWaGcbikX1K2hFVcZ7ETogG7eqdRBtbfx+JxhyRY1Od+snM88CSfuQkOgs4xQli3GrGttgY0f8BA65/pbixG9gAPkacEkexS997iuTP9BmwLmwWq1pw91c0yEQO1JnsbGHj/YfRhBV6s4FL8n5uVC0My64tisqA+8eZTeld8Zwem4XQGjoqwt2HYy1YXv0kOU8NyI0EGDz3fmqER3ex0cL+MqvWf/cnWQ6MRvGI3w/gL3+V8ueZv5qXpnY+ZH2UcrqEv7Xl74fkdqPYo53ySLQ9ZCiCitHgMjl3bk= shwezu@qq.com

5. ssh_config vs sshd_config file#

I would like to change my SSH port running Linux CentOS 6. I also noticed there’s an /etc/ssh_config file along with /etc/sshd_config. What’s the difference between the two? Should I change both?

The sshd_config is the ssh daemon (or ssh server process) configuration file. As you’ve already stated, this is the file you’ll need to modify to change the server port.

Whereas, the ssh_config file is the ssh client configuration file. The client configuration file only has bearing on when you use the ssh command to connect to another ssh host. So, in this case, you don’t need to modify it. It will be other client machines connecting to your server.

Source: Should I modify only sshd_config, or also ssh_config?

References: