python连接sftp的问题汇总

Python3.11

Python3.11

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

1、使用paramiko模块连接sftp报错:paramiko.ssh_exception.AuthenticationException: Authentication failed.

 直接上代码:

def connect_with_private_key():
    # SFTP连接参数
    hostname = 'xxxxxxxxx'
    port = 22
    username = 'xxxx'
    private_key_path = r".ssh\id_rsa"  # 替换为您的私钥路径

    # 加载私钥
    private_key = paramiko.RSAKey.from_private_key_file(private_key_path)

    # 创建SSH客户端
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    # 建立连接
    ssh.connect(hostname=hostname, port=port, username=username, pkey=private_key)

    # 创建SFTP客户端
    sftp = ssh.open_sftp()
    print("SFTP连接成功!")

    # 示例: 列出根目录文件
    print("根目录文件:", sftp.listdir('.'))

    # 关闭连接
    sftp.close()
    ssh.close()

if __name__ == "__main__":
    connect_with_private_key()

如果你确认了连接信息都是无误的情况下,还是报错了`Authentication failed`

那么接下来你需要使用第三方客户端连接sftp,我这边使用了MobaXterm软件连接是可以连接上的,那么我们可以肯定的是连接信息和防火墙都是不存在问题的,我们把范围缩小看看MobaXterm连接是不是做了什么操作?

我们可以问下大模型,把所有可能出现的情况都尝试一遍;最终确认了是服务端配置了特定的认证方法顺序

把完整的诊断代码贴上:

import paramiko
import logging
import os

# 配置详细日志
logging.basicConfig()
logging.getLogger("paramiko").setLevel(logging.DEBUG)

def diagnose_connection():
    host = 'your_host'
    port = 22
    username = 'your_username'
    key_path = '/path/to/private_key'
    
    # 检查私钥权限
    try:
        st = os.stat(key_path)
        if st.st_mode & 0o7777 != 0o600:
            print(f"警告: 私钥权限应为 600,当前为 {oct(st.st_mode)[-3:]}")
            print("尝试修复权限...")
            os.chmod(key_path, 0o600)
    except Exception as e:
        print(f"权限检查错误: {e}")
    
    # 创建 SSH 客户端
    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    
    # 尝试加载私钥
    key = None
    key_types = [
        ('RSA', paramiko.RSAKey),
        ('Ed25519', paramiko.Ed25519Key),
        ('ECDSA', paramiko.ECDSAKey)
    ]
    
    for name, key_class in key_types:
        try:
            key = key_class.from_private_key_file(key_path)
            print(f"成功加载 {name} 密钥")
            break
        except paramiko.ssh_exception.PasswordRequiredException:
            print(f"{name} 密钥需要密码")
            try:
                key = key_class.from_private_key_file(key_path, password='your_passphrase')
                print(f"使用密码成功加载 {name} 密钥")
                break
            except:
                continue
        except:
            continue
    
    if not key:
        print("无法加载任何类型的密钥")
        return
    
    # 尝试连接
    try:
        client.connect(
            hostname=host,
            port=port,
            username=username,
            pkey=key,
            timeout=10,
            allow_agent=False,
            look_for_keys=False,
            disabled_algorithms={'pubkeys': ['rsa-sha2-256', 'rsa-sha2-512']}
        )
        print("连接成功!")
        
        # 测试 SFTP
        sftp = client.open_sftp()
        files = sftp.listdir()
        print(f"找到 {len(files)} 个文件")
        sftp.close()
        
    except paramiko.AuthenticationException as e:
        print(f"认证失败: {e}")
        print("可能原因:")
        print("1. 用户名错误")
        print("2. 私钥不匹配")
        print("3. 服务器不接受此密钥类型")
    except paramiko.SSHException as e:
        print(f"SSH 错误: {e}")
    except Exception as e:
        print(f"其他错误: {e}")
    finally:
        client.close()

# 运行诊断
diagnose_connection()

最终我们连接上了!

知识点:

Paramiko 连接参数详解:allow_agentlook_for_keys 和 disabled_algorithms

这三个参数在 Paramiko 的 connect() 方法中用于控制 SSH 连接的行为,特别是身份验证过程和算法协商。下面我将详细解释每个参数的作用、使用场景和实际影响。

1.1 allow_agent=False

作用

  • 禁用 SSH 代理支持:阻止 Paramiko 尝试使用本地 SSH 代理(如 ssh-agent 或 Pageant)进行身份验证
  • 防止自动使用代理中的密钥:即使系统中有活动的 SSH 代理,也不会使用其中的密钥

使用场景

  1. 当你想显式控制身份验证凭据,避免使用系统缓存的密钥
  2. 安全敏感环境中,避免意外使用代理中的密钥
  3. 调试身份验证问题时,排除代理干扰
  4. 容器化环境中,可能没有 SSH 代理可用

默认行为

  • 如果未指定,默认为 True,Paramiko 会尝试使用 SSH 代理

示例

# 显式禁用 SSH 代理
client.connect(
    hostname='example.com',
    username='user',
    password='pass',
    allow_agent=False  # 不使用任何 SSH 代理
)

1.2 look_for_keys=False

作用

  • 禁用本地密钥查找:阻止 Paramiko 在用户主目录的 .ssh 文件夹中查找私钥文件
  • 避免自动尝试密钥认证:即使没有提供密钥,也不会尝试使用默认位置的密钥

使用场景

  1. 当你想仅使用密码认证
  2. 显式提供密钥文件时,避免额外的密钥查找
  3. 安全加固环境中,防止意外使用默认密钥
  4. 连接速度很重要时,减少不必要的密钥查找时间

默认行为

  • 如果未指定,默认为 True,Paramiko 会尝试在以下位置查找密钥:
    • ~/.ssh/id_rsa
    • ~/.ssh/id_dsa
    • ~/.ssh/id_ecdsa
    • ~/.ssh/id_ed25519

示例

# 禁用本地密钥查找
client.connect(
    hostname='example.com',
    username='user',
    password='pass',
    look_for_keys=False  # 不查找 ~/.ssh 中的密钥
)

1.3 disabled_algorithms={'pubkeys': ['rsa-sha2-256', 'rsa-sha2-512']}

作用

  • 禁用特定公钥算法:明确禁止使用指定的公钥签名算法
  • 解决算法兼容性问题:当客户端和服务器支持的算法不匹配时

参数结构

  • 接受一个字典,其中键指定算法类别,值是该类别中要禁用的算法列表
  • 本例中禁用了两种公钥算法:
    • rsa-sha2-256:使用 SHA-256 哈希的 RSA 签名
    • rsa-sha2-512:使用 SHA-512 哈希的 RSA 签名

使用场景

  1. 连接旧版 SSH 服务器(如 OpenSSH 7.2 之前版本),这些服务器不支持新的 RSA-SHA2 签名方案
  2. 解决错误:"no matching host key type" 或 "sign_and_send_pubkey: no mutual signature algorithm"
  3. 当服务器配置错误或使用自定义 SSH 实现
  4. 安全策略要求禁用特定算法

示例

# 禁用特定的公钥算法
client.connect(
    hostname='old-server.example.com',
    username='user',
    key_filename='id_rsa',
    disabled_algorithms={'pubkeys': ['rsa-sha2-256', 'rsa-sha2-512']}
)

三个参数组合使用的场景

当这三个参数一起使用时,通常是为了严格控制身份验证过程

client.connect(
    hostname='legacy-server.example.com',
    port=22,
    username='admin',
    pkey=private_key,  # 显式提供密钥对象
    allow_agent=False,  # 不使用 SSH 代理
    look_for_keys=False,  # 不在本地查找密钥
    disabled_algorithms={'pubkeys': ['rsa-sha2-256', 'rsa-sha2-512']}  # 禁用新算法
)

这种组合的典型场景:

  1. 连接旧系统:连接到不支持新 RSA-SHA2 算法的旧 SSH 服务器
  2. 安全敏感环境:精确控制使用的凭据和算法
  3. 自动化脚本:确保一致的行为,不受本地环境的影响
  4. 调试环境:排除代理和自动密钥查找的干扰

参数间的相互作用

参数影响 allow_agent影响 look_for_keys影响 disabled_algorithms
身份验证源控制代理使用控制本地密钥查找不影响身份验证源
算法选择不影响不影响限制可用算法
连接速度减少代理查询时间减少密钥查找时间可能减少算法协商时间
安全性防止意外使用代理密钥防止意外使用默认密钥可能降低安全性(禁用新算法)

您可能感兴趣的与本文相关的镜像

Python3.11

Python3.11

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值