标题: 以公私钥方式登录SSH Server 创建: 2023-02-21 12:18 更新: 2023-02-27 13:46 链接: https://scz.617.cn/unix/202302211218.txt -------------------------------------------------------------------------- 目录: ☆ 背景介绍 ☆ 生成公私钥 ☆ /etc/ssh/sshd_config ☆ $HOME/.ssh/authorized_keys ☆ WinSCP ☆ SecureCRT ☆ Linux SSH Client ☆ /var/log/auth.log 1) 找不到auth.log ☆ 远程探测服务端PubkeyAcceptedAlgorithms设置 (暂无可行方案) 1) ssh-keyscan (不可行) 2) ssh -o HostkeyAlgorithms=ssh-rsa (不可行) 3) ssh -vvv (不可行) ☆ ChatGPT ☆ RFC 4252 ☆ RFC 4253 ☆ 参考资源 -------------------------------------------------------------------------- ☆ 背景介绍 公网上有台Ubuntu 22,考虑到暴力猜测SSH密码太疯狂,应该只允许公私钥方式登录 SSH,端口应该开在非标端口。初始有个非标端口、随机生成的密码,先用密码登录, 再配置公私钥登录。意外发现两个Windows客户端公私钥登录失败,排查后发现是服 务端OpenSSH版本过高,出现向后不兼容的安全升级,而客户端较旧,两相一凑,歇 菜。出于各种综合考虑,以向后兼容为主要矛盾,对此记录一番。 从安全角度讲,C/S两侧都升至最新版是最佳选择,但现实世界中不这样干的原因有 很多;「我即宇宙」是种幼稚狂妄病,得好好治治,但对某些人来说,是绝症,治不 好的。 ☆ 生成公私钥 ssh-keygen -q -C "" -t rsa -b 4096 -N "" -m PEM -f rsa_4096 ls -l rsa_4096* ssh-keygen生成两个文件,扩展名为.pub的是公钥,没有扩展名的是私钥,公钥需要 上传到目标SSH Server。不喜欢所谓免密登录,指定了。 新版ssh-keygen默认不再是"-m PEM",而是OpenSSH自己的一种新格式。某些旧版 SecureCRT不认新格式私钥,为此必须给ssh-keygen显式指定"-m PEM"生成旧版私钥。 rsa_4096形如 -----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-128-CBC,... ... -----END RSA PRIVATE KEY----- 作为对比,OpenSSH新版私钥形如 -----BEGIN OPENSSH PRIVATE KEY----- ... -----END OPENSSH PRIVATE KEY----- 从安全性讲,应该用新版私钥,从向后兼容性讲,用旧版私钥。 rsa_4096.pub形如 ssh-rsa ...== ☆ /etc/ssh/sshd_config PermitRootLogin yes StrictModes yes Protocol 2 # RSAAuthentication yes PubkeyAuthentication yes PubkeyAcceptedAlgorithms +ssh-rsa AuthorizedKeysFile .ssh/authorized_keys PasswordAuthentication yes 将Protocol设为2,避免使用脆弱的1。注释掉RSAAuthentication,该选项只为1所用。 测试阶段将PasswordAuthentication设为yes,公私钥方式登录SSH成功后再改成no。 是否允许root远程登录看情况。 重启sshd使配置生效 service sshd restart ☆ $HOME/.ssh/authorized_keys 在目标SSH Server上执行 mkdir -p $HOME/.ssh chmod 0700 $HOME/.ssh cat rsa_4096.pub >> $HOME/.ssh/authorized_keys chown -R $HOME/.ssh chmod 0600 $HOME/.ssh/authorized_keys 其实就是将公钥内容放入authorized_keys,chown、chmod是防止sshd以不安全为由 拒绝使用authorized_keys。 $HOME/.ssh/known_hosts(0644)是Linux作为SSH Client使用时自动生成的,与本文 无关。 ☆ WinSCP WinSCP和PuTTY必须使用some.ppk这种格式的私钥,可用puttygen完成格式转换 -------------------------------------------------------------------------- \putty\puttygen.exe Load rsa_4096 Save private key rsa_4096.ppk -------------------------------------------------------------------------- rsa_4096.ppk形如 -------------------------------------------------------------------------- PuTTY-User-Key-File-2: ssh-rsa Encryption: aes256-cbc Comment: imported-openssh-key Public-Lines: 12 ... Private-Lines: 28 ... Private-MAC: ... -------------------------------------------------------------------------- WinSCP需要对目标站点配置私钥 -------------------------------------------------------------------------- WinSCP Advanced Site Settings SSH Authentication Private key file rsa_4096.ppk -------------------------------------------------------------------------- 我用WinSCP 5.17.8,Ubuntu 22中是OpenSSH 8.9p1,这两个C/S配对时存在兼容性问 题。若服务端没有"PubkeyAcceptedAlgorithms +ssh-rsa",WinSCP 5.17.8公私钥登 录时提示"Server refused our key";WinSCP 5.20做了安全增强,无需修改服务端 配置。 参[3],里面有一段 2021-10-12 17:36, OpenSSH 8.8 disabled ssh-rsa by default. Until WinSCP 5.20 is released, add this to server's sshd_config to re-enable it: PubkeyAcceptedAlgorithms +ssh-rsa Ubuntu 20中是OpenSSH_8.2p1,没这幺蛾子。 ☆ SecureCRT SecureCRT 7.3.3密码登录Ubuntu 22时失败 Key exchange failed. No compatible key exchange method. The server supports these methods: curve25519-sha256, curve25519-sha256@libssh.org, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, sntrup761x25519-sha512@openssh.com, diffie-hellman-group-exchange-sha256, diffie-hellman-group16-sha512, diffie-hellman-group18-sha512, diffie-hellman-group14-sha256 No compatible cipher. The server supports these ciphers: chacha20-poly1305@openssh.com, AES-128-CTR, AES-192-CTR, AES-256-CTR, aes128-gcm@openssh.com, aes256-gcm@openssh.com 意思是说服务端支持上面这一堆,但客户端当前配置不支持。 检查SecureCRT的"Session Options",下面是一种方案,充分非必要 -------------------------------------------------------------------------- Connection SSH2 Authentication Password Key exchange ecdh-sha2-nistp256 Advanced Cipher AES-256-CTR MAC SHA2-256 -------------------------------------------------------------------------- 先用Password登录成功,再配置公私钥登录 -------------------------------------------------------------------------- Connection SSH2 Authentication Publickey Properties Use session public key setting Use identity or certificate file rsa_4096 -------------------------------------------------------------------------- SecureCRT 7.3.3不认OpenSSH新版私钥 ssh-keygen -q -C "test" -t rsa -b 4096 -N "test" -f test_4096 用test_4096时,SecureCRT 7.3.3提示 -------------------------------------------------------------------------- The private key file could not be found Note that the public key file and private key file must have the same name (e.g., "Identity.pub" and "Identity") and must be located in the same folder. Unknown file format -------------------------------------------------------------------------- 过去的套路突然不灵,起初我挺懵逼的,后来无意中发现新旧私钥格式不一样,问 ChatGPT如何生成旧版私钥,从它的回答中意识到ssh-keygen可以指定生成哪种格式 的私钥,在man手册中看到 -------------------------------------------------------------------------- By default OpenSSH will write newly-generated private keys in its own format. Setting a format of "PEM" when generating a supported private key type will cause the key to be stored in the legacy PEM private key format. -------------------------------------------------------------------------- ssh-keygen的缺省值变了,为了保持向后兼容性,应该"ssh-keygen -m PEM"。 SecureCRT 7.3.3与Ubuntu 22中的OpenSSH 8.9p1,这两个C/S配对时存在兼容性问题。 若服务端没有"PubkeyAcceptedAlgorithms +ssh-rsa",SecureCRT 7.3.3公私钥登录 时提示 -------------------------------------------------------------------------- Public-key authentication with the server for user scz failed. Please verify username and public/private key pair. The client has disconnected from the server. Reason: Unable to authenticate using any of the configured authentication methods. -------------------------------------------------------------------------- 假设没有先验知识,只根据上述提示,很难定位PubkeyAcceptedAlgorithms,这个提 示不合格。新版SecureCRT应该有安全增强,无需修改服务端配置,未实测。 实测SecureCRT 7.3.3不支持rsa-sha2-512、ecdsa、ed25519。 ☆ Linux SSH Client 服务端没有"PubkeyAcceptedAlgorithms +ssh-rsa"时,旧版SecureCRT、WinSCP公私 钥登录失败,之前以为是不加此配置时服务端不认RSA公钥。意外发现服务端不加此 配置时Linux SSH Client公私钥登录成功,用的是同一套RSA公私钥,那就不是服务 端不认RSA公钥,应该有其他合理解释,与协商过程强相关,这让我对公私钥登录流 程产生好奇。 用Linux SSH Client时,注意私钥权限最小化,否则拒绝使用 chmod 0400 rsa_4096 ssh -i rsa_4096 -p @ 查看SSH Server/Client版本 $ sshd -V OpenSSH_8.9p1 Ubuntu-3, OpenSSL 3.0.2 15 Mar 2022 $ ssh -V OpenSSH_8.4p1 Debian-3, OpenSSL 1.1.1i 8 Dec 2020 查看客户端连接指定站点时所用配置 $ ssh -G -i rsa_4096 -p @ ... hostkeyalgorithms ...,rsa-sha2-512,rsa-sha2-256,ssh-rsa ... pubkeyacceptedkeytypes ...,rsa-sha2-512,rsa-sha2-256,ssh-rsa ... 查看客户端连接指定站点时更详细的信息 ssh -vvv -i rsa_4096 -p @ 查看客户端支持的(签名)算法 $ ssh -Q sig ssh-ed25519 sk-ssh-ed25519@openssh.com ssh-rsa rsa-sha2-256 rsa-sha2-512 ssh-dss ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 sk-ecdsa-sha2-nistp256@openssh.com webauthn-sk-ecdsa-sha2-nistp256@openssh.com rsa-sha2-512/rsa-sha2-256/ssh-rsa三者公私钥都用RSA,签名算法分别用SHA-512、 SHA-256、SHA-1。 参[1] -------------------------------------------------------------------------- HostkeyAlgorithms the public key algorithms accepted for an SSH server to authenticate itself to an SSH client PubkeyAcceptedKeyTypes (ssh/sshd): the public key algorithms that will be attempted by the client, and accepted by the server for public-key authentication (e.g. via .ssh/authorized_keys) -------------------------------------------------------------------------- 客户端用PubkeyAcceptedKeyTypes指定用哪种(签名)算法,而非HostKeyAlgorithms。 rm $HOME/.ssh/known_hosts ssh -i rsa_4096 -o PubkeyAcceptedKeyTypes=rsa-sha2-512 -p @ 上述命令登录成功,等价于无"-o"参数的默认情形;用rsa-sha2-256也能成功。 rm $HOME/.ssh/known_hosts ssh -i rsa_4096 -o PubkeyAcceptedKeyTypes=ssh-rsa -p @ 上述命令登录失败,相当于模拟了旧版SecureCRT、WinSCP登录失败的情形,后两者 无法指定PubkeyAcceptedKeyTypes。 ☆ /var/log/auth.log 前述登录失败是旧版Client对新版Server,也有反过来的,同样可能失败,参[2]。 C/S两侧在协商过程中向对方展示己方支持的算法,只要存在交集,就能成功,反之 失败。从运维角度看,关注auth.log,从中发现失败的深层次原因,再在C/S两侧做 相应调整,领会精神,此处不一一排列组合了。 tail -f /var/log/auth.log 旧版SecureCRT登录失败时,auth.log指明应修改PubkeyAcceptedAlgorithms userauth_pubkey: key type ssh-rsa not in PubkeyAcceptedAlgorithms [preauth] Linux SSH Client模拟登录失败时,可见同样的日志。登录成功时看到 Accepted publickey for scz from port ssh2: RSA SHA256:... 1) 找不到auth.log 正常安装的Ubuntu 22有auth.log,但minimized版本可能找不到auth.log,换个方式 查看SSH登录日志 journalctl -u ssh.service | tail -20 或者 aptitude install rsyslog service rsyslog restart 这会重新启用auth.log ☆ 远程探测服务端PubkeyAcceptedAlgorithms设置 (暂无可行方案) 原始意图是找一种非穷举方案,直接获取服务端支持的签名算法,暂无可行方案。 1) ssh-keyscan (不可行) ssh-keyscan -T 10 -4 -t rsa,dsa,ecdsa,ed25519 -p 上述命令得到的是SSH Server的可用public host key列表,当SSH Client选用其中 某种算法成功后,会在客户端~/.ssh/known_hosts中保存服务端相应的public host key。 ssh-keyscan无法探测服务端PubkeyAcceptedAlgorithms设置,无论服务端是否配置 "PubkeyAcceptedAlgorithms +ssh-rsa",ssh-keyscan得到的public host key列表 中均有ssh-rsa算法。这很好理解,ssh-keyscan获取的信息本非用于此目的。 2) ssh -o HostkeyAlgorithms=ssh-rsa (不可行) ssh -o HostkeyAlgorithms=ssh-rsa -p @ 无论服务端是否配置"PubkeyAcceptedAlgorithms +ssh-rsa",上述命令均返回 Unable to negotiate with port : no matching host key type found. Their offer: rsa-sha2-512,rsa-sha2-256,ecdsa-sha2-nistp256,ssh-ed25519 意味着无法用上述命令探测服务端PubkeyAcceptedAlgorithms设置 3) ssh -vvv (不可行) rm $HOME/.ssh/known_hosts ssh -vvv -i rsa_4096 -p @ ssh -vvv -i rsa_4096 -o PubkeyAcceptedKeyTypes=ssh-rsa -p @ "ssh -vvv"会显示登录认证过程中相关细节,比如 debug1: Authentications that can continue: publickey,password debug3: start over, passed a different list publickey,password 表示服务端同时支持公私钥及口令登录,若只允许公私钥登录,此处无password。 debug3: sign_and_send_pubkey: signing using ssh-rsa ... debug3: send packet: type 50 debug2: we sent a publickey packet, wait for reply debug3: receive packet: type 51 此部分第一行表示客户端使用ssh-rsa签名算法,"-o PubkeyAcceptedKeyTypes="可 设置此算法,默认是rsa-sha2-512。最后一行"type 51"表示失败,"type 52"表示成 功。 注意到 debug1: kex_input_ext_info: server-sig-algs=<...,ssh-rsa,rsa-sha2-256,rsa-sha2-512,...> 无论服务端是否配置"PubkeyAcceptedAlgorithms +ssh-rsa",上行始终包含ssh-rsa, 无法从"ssh -vvv"输出中看出任何与之对应的差异,其他行也无差异。 ☆ ChatGPT 我没看过OpenSSH源码,也不了解公私钥登录流程,索性让ChatGPT忽悠忽悠我。粗看 了两眼,答得不算离谱,有一定可信度。 -------------------------------------------------------------------------- Q: scz OpenSSH公私钥登录认证时,大致流程是什么? A: ChatGPT 1. 用户生成一对公私钥,私钥存储在本地计算机上,公钥复制到远程服务器上 2. 上传公钥到服务器,将公钥复制~/.ssh/authorized_keys 3. SSH客户端连接服务器,客户端将本地公钥发送到服务器 4. 服务器收到客户端发送的公钥,与authorized_keys中的公钥列表进行匹配 5. 若服务器成功验证了公钥,会用该公钥加密一个随机数,并将其发送给客户端 6. 客户端收到服务器发送的加密随机数,用本地私钥对其解密 7. 客户端和服务器拥有同一随机数,它们用之作种子,利用密钥协商算法生成对称 加密密钥 8. 客户端和服务器用前述对称加密密钥进行后续通信 9. 公私钥只用于登录认证阶段,一旦认证通过,客户端和服务器之间的通信使用对 称加密通信 Q: scz 在此过程中,signature algorithm 体现在哪里? A: ChatGPT 客户端向服务器发送本地公钥,并使用私钥生成一个数字签名(signature)。服务器 收到客户端发送的公钥和数字签名,与authorized_keys中的公钥进行匹配,并校验 数字签名,若验证通过,认为客户端合法,可以继续。 Q: scz 假设公私钥保持不变,新版OpenSSH服务端需要"PubkeyAcceptedAlgorithms +ssh-rsa", 否则某些旧版客户端公私钥登录失败,某些新版客户端公私钥登录成功,请从算法角 度简述造成这种现象的原因 A: ChatGPT 造成这种现象的原因是OpenSSH公私钥登录认证过程中涉及的算法版本升级导致的不 兼容。OpenSSH公私钥登录认证涉及到多种算法,包括加密算法、HASH算法和签名算 法等,这些算法可能随时间推移而发生改变,例如在某个版本的OpenSSH中,可能使 用SHA-1来计算数字签名,但在新版中,可能改为更安全的算法,例如SHA-256。为了 确保兼容性,需要使用相同的算法,通过适当的参数配置来确保新旧版本之间可以正 常通信。 Q: scz 你不是一般的牛逼 A: ChatGPT 感谢夸奖!我只是一个机器人。 -------------------------------------------------------------------------- 上述ChatGPT回答只是不离谱,但不要当成标准答案,更多细节参看RFC 4252/4253。 ☆ RFC 4252 7. Public Key Authentication Method: "publickey" -------------------------------------------------------------------------- To perform actual authentication, the client MAY then send a signature generated using the private key. The client MAY send the signature directly without first verifying whether the key is acceptable. The signature is sent using the following packet: byte SSH_MSG_USERAUTH_REQUEST string user name string service name string "publickey" boolean TRUE string public key algorithm name string public key to be used for authentication string signature The value of signature is a signature by the corresponding private key over the following data, in the following order: string session identifier byte SSH_MSG_USERAUTH_REQUEST string user name string service name string "publickey" boolean TRUE string public key algorithm name string public key to be used for authentication When the server receives this message, it MUST check whether the supplied key is acceptable for authentication, and if so, it MUST check whether the signature is correct. If both checks succeed, this method is successful. -------------------------------------------------------------------------- ☆ RFC 4253 6.6. Public Key Algorithms -------------------------------------------------------------------------- The following public key and/or certificate formats are currently defined: ssh-rsa RECOMMENDED sign Raw RSA Key public keys are encoded as follows: string public key format identifier byte[n] key data Signatures are encoded as follows: string signature format identifier (as specified by the public key format) byte[n] signature blob in format specific encoding. The "ssh-rsa" key format has the following specific encoding: string "ssh-rsa" mpint e mpint n Here the 'e' and 'n' parameters form the signature key blob. Signing and verifying using this key format is performed according to the RSASSA-PKCS1-v1_5 scheme in [RFC3447] using the SHA-1 hash. The resulting signature is encoded as follows: string "ssh-rsa" string rsa_signature_blob The value for 'rsa_signature_blob' is encoded as a string containing s (which is an integer, without lengths or padding, unsigned, and in network byte order). -------------------------------------------------------------------------- ☆ 参考资源 [1] OpenSSH Legacy Options https://www.openssh.com/legacy.html https://www.openssh.com/txt/release-8.8 (Potentially-incompatible changes) OpenSSH 8.3 released (and ssh-rsa deprecation notice) https://lwn.net/Articles/821544/ [2] SSH without password does not work after upgrading from 18.04 to 22.04 - [2022-04-23] https://askubuntu.com/questions/1404049/ssh-without-password-does-not-work-after-upgrading-from-18-04-to-22-04 Ubuntu 22.04 SSH the RSA key isn't working since upgrading from 20.04 - [2022-05-17] https://askubuntu.com/questions/1409105/ubuntu-22-04-ssh-the-rsa-key-isnt-working-since-upgrading-from-20-04 SSH server gives "userauth_pubkey: key type ssh-rsa not in PubkeyAcceptedAlgorithms [preauth]" when connecting with Putty - [2022-10-19] https://unix.stackexchange.com/questions/721606/ssh-server-gives-userauth-pubkey-key-type-ssh-rsa-not-in-pubkeyacceptedalgorit (ssh -Q sig) [3] "Server refused our key" after updating to Ubuntu 22.04 beta on a LAMP stack - [2022-04-09] https://winscp.net/forum/viewtopic.php?t=32133 Bug 1952 - Support rsa-sha2-256 and rsa-sha2-512 SSH public key algorithms https://winscp.net/tracker/1952 [4] The Secure Shell (SSH) Protocol Assigned Numbers https://www.rfc-editor.org/rfc/rfc4250 The Secure Shell (SSH) Authentication Protocol https://www.rfc-editor.org/rfc/rfc4252 The Secure Shell (SSH) Transport Layer Protocol https://www.rfc-editor.org/rfc/rfc4253