Paramiko连接SFTP遇BadHostKeyException,求正确私钥连接方式
解决Paramiko连接SFTP的BadHostKeyException问题
首先明确:你遇到的核心问题是本地配置的主机密钥和服务器实际返回的不匹配,而AutoAddPolicy()跳过了主机密钥验证,确实存在中间人攻击风险,绝不是生产环境的合理选择。
错误根源
你提到sftp.pem和host.pem都是私钥——这是关键错误:主机密钥需要的是服务器的公钥,用来验证服务器身份;而sftp.pem才是你的客户端私钥,用来证明自身身份。把私钥当成主机公钥添加,必然导致验证失败。
正确的连接步骤
1. 获取服务器真实的主机公钥
有两种可靠方式获取:
- 方式一:从本地SSH已知主机文件提取
用SSH命令手动连接一次服务器:ssh username@##.###.##.#,确认信任后,服务器的主机公钥会被写入~/.ssh/known_hosts文件。直接从这个文件里找到对应主机的条目即可。 - 方式二:用ssh-keyscan命令直接获取
在终端执行:
输出内容就是服务器的RSA主机公钥,复制保存为一个公钥文件(比如ssh-keyscan -t rsa ##.###.##.#server_host_key.pub)。
2. 正确编写Paramiko代码
推荐两种安全的实现方式:
方式一:加载系统已知主机密钥(最简便,和SSH客户端保持一致)
直接复用~/.ssh/known_hosts里的配置,无需手动添加:
import paramiko private_key_path = "./sftp.pem" client = paramiko.SSHClient() # 加载系统默认的known_hosts文件 client.load_system_host_keys() # 如果你的known_hosts在自定义路径,改用:client.load_host_keys("/path/to/your/known_hosts") # 发起连接 client.connect( hostname='##.###.##.#', username='username', key_filename=private_key_path )
方式二:手动添加指定的主机公钥
如果不想依赖系统known_hosts,可以手动加载获取到的服务器公钥:
import paramiko private_key_path = "./sftp.pem" server_host_key_path = "./server_host_key.pub" # 你保存的服务器公钥文件 client = paramiko.SSHClient() hostname = '##.###.##.#' # 读取并加载服务器主机公钥 with open(server_host_key_path, 'r') as f: host_keys = paramiko.util.load_host_keys(f) host_key = host_keys[hostname]['ssh-rsa'] client.get_host_keys().add(hostname, 'ssh-rsa', host_key) # 发起连接 client.connect( hostname=hostname, username='username', key_filename=private_key_path )
额外注意事项
- 确保主机密钥类型匹配:如果服务器用的是ECDSA或ED25519密钥,要把命令和代码里的
ssh-rsa改成对应类型(比如ssh-ed25519)。 - 主机标识要一致:如果用IP连接服务器,就添加IP对应的主机密钥;如果用域名,就用域名对应的,不要混用。
- 私钥权限要正确:确保
sftp.pem的文件权限是600(仅当前用户可读可写),否则Paramiko可能拒绝加载。
内容的提问来源于stack exchange,提问作者d.b
相关产品推荐
相关产品推荐

