Paramiko SSHClient连接SFTP服务器认证失败问题求助
问题描述
使用相同凭据,WinSCP、pysftp以及直接使用Paramiko Transport均可正常连接SFTP服务器,但使用Paramiko SSHClient却抛出认证失败错误:
paramiko.ssh_exception.AuthenticationException: Authentication failed.
且完全相同的代码在同事环境中可正常运行。
代码示例
import pysftp from base64 import decodebytes import paramiko username = "my_username" password = "my_secret_password" hostname = "ftp.hostname.tld" directory = "/protected/directory" port = 22 keydata = b"""AAAAB...TuQ==""" key = paramiko.RSAKey(data=decodebytes(keydata)) # PYSFTP 可以正常工作! cnopts = pysftp.CnOpts() cnopts.hostkeys.add(hostname, 'ssh-rsa', key) with pysftp.Connection(host=hostname, username=username, password=password, cnopts=cnopts) as sftp: files = sftp.listdir_attr(directory) test = "test" # 直接用Paramiko Transport也可以正常工作! with paramiko.Transport((hostname,port)) as transport: transport.connect( hostkey=key, username=username, password=password ) with paramiko.SFTPClient.from_transport(transport) as sftp: files = sftp.listdir_attr(directory) test = "test" # 用SSHClient建立连接的版本无法工作 ssh_client = paramiko.SSHClient() ssh_client.get_host_keys().add(hostname=hostname, keytype="ssh-rsa", key=key) ssh_client.connect( hostname=hostname, username=username, password=password, port=port ) sftp = ssh_client.open_sftp() files = sftp.listdir_attr(directory) test = "test"
失败会话的Paramiko日志
DEBUG:paramiko.transport:starting thread (client mode): 0x5dad0e50 DEBUG:paramiko.transport:Local version/idstring: SSH-2.0-paramiko_3.1.0 DEBUG:paramiko.transport:Remote version/idstring: SSH-2.0-srtSSHServer_11.00 INFO:paramiko.transport:Connected (version 2.0, client srtSSHServer_11.00) DEBUG:paramiko.transport:=== Key exchange possibilities === DEBUG:paramiko.transport:kex algos: diffie-hellman-group14-sha256, diffie-hellman-group-exchange-sha256, diffie-hellman-group14-sha1, diffie-hellman-group-exchange-sha1, diffie-hellman-group1-sha1, diffie-hellman-group-exchange-sha512@ssh.com DEBUG:paramiko.transport:server key: ssh-rsa DEBUG:paramiko.transport:client encrypt: aes256-ctr, aes128-ctr, aes256-cbc, twofish256-cbc, aes128-cbc, twofish256-ctr, aes192-ctr, twofish192-ctr, twofish128-ctr, twofish128-cbc DEBUG:paramiko.transport:server encrypt: aes256-ctr, aes128-ctr, aes256-cbc, twofish256-cbc, aes128-cbc, twofish256-ctr, aes192-ctr, twofish192-ctr, twofish128-ctr, twofish128-cbc DEBUG:paramiko.transport:client mac: hmac-sha3-512, hmac-sha3-384, hmac-sha3-256, hmac-sha3-224, hmac-sha2-512, hmac-sha2-384, hmac-sha2-256, hmac-sha2-224, hmac-sha1 DEBUG:paramiko.transport:server mac: hmac-sha3-512, hmac-sha3-384, hmac-sha3-256, hmac-sha3-224, hmac-sha2-512, hmac-sha2-384, hmac-sha2-256, hmac-sha2-224, hmac-sha1 DEBUG:paramiko.transport:client compress: none DEBUG:paramiko.transport:server compress: none DEBUG:paramiko.transport:client lang: <none> DEBUG:paramiko.transport:server lang: <none> DEBUG:paramiko.transport:kex follows: False DEBUG:paramiko.transport:=== Key exchange agreements === DEBUG:paramiko.transport:Kex: diffie-hellman-group-exchange-sha256 DEBUG:paramiko.transport:HostKey: ssh-rsa DEBUG:paramiko.transport:Cipher: aes128-ctr DEBUG:paramiko.transport:MAC: hmac-sha2-256 DEBUG:paramiko.transport:Compression: none DEBUG:paramiko.transport:=== End of kex handshake === DEBUG:paramiko.transport:Got server p (2048 bits) DEBUG:paramiko.transport:kex engine KexGexSHA256 specified hash_algo <built-in function openssl_sha256> DEBUG:paramiko.transport:Switch to new keys ... DEBUG:paramiko.transport:Trying discovered key b'f28c2e56806b573d7fc45b9722242e5b' in C:\Users\my-user/.ssh/id_rsa DEBUG:paramiko.transport:userauth is OK DEBUG:paramiko.transport:Finalizing pubkey algorithm for key of type 'ssh-rsa' DEBUG:paramiko.transport:Our pubkey algorithm list: ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-rsa'] DEBUG:paramiko.transport:Server did not send a server-sig-algs list; defaulting to our first preferred algo ('rsa-sha2-512') DEBUG:paramiko.transport:NOTE: you may use the 'disabled_algorithms' SSHClient/Transport init kwarg to disable that or other algorithms if your server does not support them! INFO:paramiko.transport:Authentication (publickey) failed. INFO:paramiko.transport:Disconnect (code 2): unexpected service request
排查方向
从日志和代码差异来看,重点检查以下几点:
强制指定认证方式:SSHClient默认优先尝试本地公钥认证(日志显示它在尝试
C:\Users\my-user/.ssh/id_rsa),而其他连接方式仅用密码认证。在connect方法中添加look_for_keys=False和allow_agent=False,强制只使用密码认证:ssh_client.connect( hostname=hostname, username=username, password=password, port=port, look_for_keys=False, allow_agent=False )禁用不兼容的公钥签名算法:日志提示服务器不支持
rsa-sha2-512算法,而SSHClient默认优先使用该算法。初始化SSHClient时禁用该算法:ssh_client = paramiko.SSHClient() ssh_client.disabled_algorithms = {'pubkeys': ['rsa-sha2-512']} ssh_client.get_host_keys().add(hostname=hostname, keytype="ssh-rsa", key=key) ssh_client.connect(...)检查本地SSH配置冲突:你的环境可能存在全局SSH配置(如
C:\Users\my-user/.ssh/config)影响SSHClient行为,而同事环境无此配置。临时重命名.ssh目录后再测试连接。对比Paramiko版本:不同版本的Paramiko可能存在兼容性差异,执行
pip show paramiko查看本地版本,切换到和同事相同的版本测试。排查代理或环境变量差异:你的环境可能运行了SSH代理(如Pageant),导致SSHClient尝试使用代理中的密钥认证。添加
allow_agent=False可避免此问题。
内容的提问来源于stack exchange,提问作者jakobdo

