前言
我负责维护的一套系统,由于面向银行收款,搭建了2个实例的sftp服务器,前端使用F5做负载均衡。
但客户端登录时,时不时会有因指纹(fingerprint)变化出现的中间人攻击(man-in-the-middle attack)提醒。
起初认为是两个实例没有同步.ssh目录内的秘钥导致,把秘钥从一台实例拷贝到另外一台,问题仍没有解决。
1 | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
为什么要使用fingerprint?
SSH 连接在第一次连接到服务器时最容易受到攻击。
在第一次连接到服务器后,SSH 客户端会记录其指纹。
如果该指纹随后发生变化,即有人试图诱骗连接到恶意服务器,这时SSH 客户端将发出警告,指纹已发生变化。
当我们首次连接到VPS 服务器时,客户端无法记录其指纹并验证其是否正确。
因此,攻击者可以成功执行中间人攻击,确保从一开始就连接到正确服务器的唯一方法是手动检查SSH密钥指纹。
如何查看服务端的fingerprint?
在检查指纹(fingerprint)之前,需要知道生成指纹使用的算法。
比如客户端A连接客户端B,首次连接时出现提示:
1 | wise@wise-desktop:~$ sftp -oPort=9222 karbin@127.0.0.1 |
上面的信息提示,密钥使用ED25519算法,并使用SHA256哈希处理。
密钥算法也可能是 ECDSA、RSA 和 DSA,并且哈希算法可能是 MD5 而不是 SHA256。
知道了生成算法,就要找密钥证书文件,该文件位于/etc/ssh/ssh_host_ed25519_key.pub
1 | # 执行命令 |
下面提供常见的秘钥生成fingerprint的算法:
1 | ED25519: |
https://bitlaunch.io/blog/how-to-check-your-ssh-key-fingerprint/
如何解决sftp实例之间的fingerprint指纹差异?
知道了fingerprint生成原理,终于有了解决方案,两台sftp server实例,需要同步/etc/ssh/ssh_host*开头的秘钥文件。
从一台拷贝到另外一台,覆盖前先备份,覆盖后重启sshd进程即可。
试验验证
本地使用vmware启动两台装有Centos7系统实例,并分别获取fingerprint:
192.168.0.128
1
2
3# cd /etc/ssh
# ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
256 SHA256:qD4inP4dspacQdGKPUu6q8Pa151jboZzcUYF4VInPaY no comment (ED25519)192.168.0.162
1
2
3# cd /etc/ssh
# ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
256 SHA256:Q+GouijSIb+PjW9pOzUOAr2Rb/DD6HzO3dmOxF2gFfY no comment (ED25519)
本地树莓派(Raspberry)设备,使用nginx提供的stream模块, 通过9222端口,代理后端两个实例的sftp服务。
(nginx使用docker部署)
1 | # nginx.conf, 加在http模块的上方。 |
以上,nginx配置的stream模块,根据客户端地址的Hash值,转发到某一个后端实例。
理论上,只要客户端网络条件不发生变化,初次信任sftp服务的fingerprint后,是不会有问题发生的。
在树莓派执行登录命令:
1 | wise@wise-desktop:~$ sftp -oPort=9222 karbin@127.0.0.1 |
以上,说明nginx将请求转发给 192.168.0.128
为了确认转发实例,我们将128从nginx代理池移除,并重启nginx,如下:
1 | stream { |
重新执行sftp登录命令:
1 | wise@wise-desktop:~$ sftp -oPort=9222 karbin@127.0.0.1 |
以上,根据打印的fingerprint,确认此次请求已转发到162
下面执行密钥同步,将128的密钥,拷贝到162
1 | # 登录162,执行拷贝: |
树莓派重新执行sftp登录命令,结果:
1 | wise@wise-desktop:~$ sftp -oPort=9222 karbin@127.0.0.1 |
以上,可以证明,客户端首次登录sftp,弹出的fingerprint,是根据/etc/ssh目录下的全局主机密钥生成的。
当使用负载均衡设备,后端挂载多个sftp实例时,需要同步实例之间的密钥证书。
系统范围的配置文件
/etc/ssh/moduli
包含用于 Diffie-Hellman 密钥交换的 Diffie-Hellman 组,这对于构建安全传输层至关重要。在 SSH 会话开始时交换密钥时,会创建一个共享的秘密值,任何一方都无法单独确定该值。然后使用此值提供主机身份验证。/etc/ssh/ssh_config
默认的 SSH 客户端配置文件。请注意,~/.ssh/config如果存在,它将被覆盖。/etc/ssh/sshd_config
守护进程的配置文件sshd。/etc/ssh/ssh_host_dsa_key
守护进程使用的 DSA 私钥sshd。/etc/ssh/ssh_host_dsa_key.pub
守护进程使用的 DSA 公钥sshd。/etc/ssh/ssh_host_key
sshd守护进程用于 SSH 协议版本 1 的RSA 私钥。/etc/ssh/ssh_host_key.pub
sshd守护进程用于 SSH 协议版本 1 的RSA 公钥。/etc/ssh/ssh_host_rsa_key
sshd守护进程用于 SSH 协议第 2 版的RSA 私钥。/etc/ssh/ssh_host_rsa_key.pub
sshd守护进程用于 SSH 协议第 2 版的RSA 公钥。/etc/pam.d/sshd
守护进程的 PAM 配置文件sshd。/etc/sysconfig/sshd
服务的配置文件sshd。
用户特定的配置文件
~/.ssh/authorized_keys
保存服务器的授权公钥列表。
当客户端连接到服务器时,服务器通过检查存储在此文件中的签名公钥来验证客户端的身份。~/.ssh/id_dsa
包含用户的 DSA 私钥。~/.ssh/id_dsa.pub
用户的 DSA 公钥。~/.ssh/id_rsa
sshSSH 协议第 2 版使用的 RSA 私钥。~/.ssh/id_rsa.pub
sshSSH 协议第 2 版使用的 RSA 公钥。~/.ssh/identity
sshSSH 协议版本 1使用的 RSA 私钥。~/.ssh/identity.pub
sshSSH 协议版本 1使用的 RSA 公钥。~/.ssh/known_hosts
包含用户访问的 SSH 服务器的 DSA 主机密钥。此文件对于确保 SSH 客户端连接到正确的 SSH 服务器非常重要。