如何通过远程服务器上的
SSHClient
进行SFTP传输?我有一个本地主机和两个远程主机。远程主机是备份服务器和Web服务器。我需要在备份服务器上找到必要的备份文件,并通过 SFTP 将其放在 Web 服务器上。如何使 Paramiko 的 SFTP 传输与 Paramiko 的 SSHClient
一起工作?
paramiko.SFTPClient
用法示例:
import paramiko
paramiko.util.log_to_file("paramiko.log")
# Open a transport
host,port = "example.com",22
transport = paramiko.Transport((host,port))
# Auth
username,password = "bar","foo"
transport.connect(None,username,password)
# Go!
sftp = paramiko.SFTPClient.from_transport(transport)
# Download
filepath = "/etc/passwd"
localpath = "/home/remotepasswd"
sftp.get(filepath,localpath)
# Upload
filepath = "/home/foo.jpg"
localpath = "/home/pony.jpg"
sftp.put(localpath,filepath)
# Close
if sftp: sftp.close()
if transport: transport.close()
接受的答案“有效”。但由于使用了低级
Transport
类,它绕过了主机密钥验证,这是一个安全缺陷,因为它使代码容易受到 中间人攻击。
SSHClient
,它可以验证主机密钥:
import paramiko
paramiko.util.log_to_file("paramiko.log")
ssh = paramiko.SSHClient()
ssh.connect(host, username='user', password='password')
# or
# key = paramiko.RSAKey.from_private_key_file('id_rsa')
# ssh.connect(host, username='user', pkey=key)
sftp = ssh.open_sftp()
sftp.get(remotepath, localpath)
# or
sftp.put(localpath, remotepath)
验证主机密钥的详细信息请参见:
Paramiko“未知服务器”
如果你有SSHClient,你也可以使用
open_sftp()
:
import paramiko
# lets say you have SSH client...
client = paramiko.SSHClient()
sftp = client.open_sftp()
# then you can use upload & download as shown above
...
除了第一个答案(很好但取决于用户名/密码)之外,以下还展示了如何使用 ssh 密钥:
from paramiko import Transport, SFTPClient, RSAKey
key = RSAKey(filename='path_to_my_rsakey')
con = Transport('remote_host_name_or_ip', 22)
con.connect(None,username='my_username', pkey=key)
sftp = SFTPClient.from_transport(con)
sftp.listdir(path='.')
对于那些需要与需要私钥的 ssh/sftp 服务器集成并希望使用特定公钥对已知主机执行主机密钥验证的人,这里是带有 paramiko 的代码片段:
import paramiko
sftp_hostname = "target.hostname.com"
sftp_username = "tartgetHostUsername"
sftp_private_key = "/path/to/private_key_file.pvt"
sftp_private_key_password = "private_key_file_passphrase_if_it_encrypted"
sftp_public_key = "/path/to/public_certified_file.pub"
sftp_port = 22
remote_path = "."
target_local_path = "/path/to/target/folder"
ssh = paramiko.SSHClient()
# Load target host public cert for host key verification
ssh.load_host_keys(sftp_public_key)
# Load encrypted private key and ssh connect
key = paramiko.RSAKey.from_private_key_file(sftp_private_key, sftp_private_key_password)
ssh.connect(host=sftp_hostname, port=sftp_port, username=sftp_username, pkey=key)
# Get the sftp connection
sftp_connection = ssh.open_sftp()
directory_list = sftp_connection.listdir(remote_path)
# ...
if sftp_connection: sftp_connection.close()
if ssh: ssh.close()
注意,仅支持经典Openssh格式的证书,否则需要使用以下命令进行转换(也适用于最新的Openssh格式):
$chmod 400 /path/to/private_key_file.pvt
$ssh-keygen -p -f /path/to/private_key_file.pvt -m pem -P <currentPassphrase> -N <newPassphrase>
为了避免中间人攻击,重要的是不要使用
paramiko.AutoAddPolicy()
并按上述方式以编程方式加载公共主机密钥或从 ~/.ssh/known_hosts
"<host_name> ssh-rsa AAAAB3NzaC1yc2EAAAA..."
$ssh-keyscan target.hostname.com
命令下载它。
上面的代码是我发现在连接过程中避免出现以下错误的唯一方法:
paramiko.ssh_exception.SSHException: Server 'x.y.z' not found in known_hosts
使用以下方式加载公共证书也会提示此错误:
key = paramiko.RSAKey(data=decodebytes(sftp_public_key))
ssh_client.get_host_keys().add(sftp_hostname, 'ssh-rsa', key)
此外,以下代码无法让我加载证书(也尝试通过以 Base64 编码证书):
ssh_client=paramiko.SSHClient()
rsa_key = paramiko.RSAKey.from_private_key_file(sftp_private_key, sftp_private_key_password)
rsa_key.load_certificate(sftp_public_key)
它总是以:
结束 File "/usr/local/lib/python3.9/site-packages/paramiko/pkey.py", line 720, in from_string
key_blob = decodebytes(b(fields[1]))
File "/usr/lib64/python3.9/base64.py", line 538, in decodebytes
return binascii.a2b_base64(s)
binascii.Error: Incorrect padding
上面的代码适用于 SFTP 与 GoAnywhere 的集成。
我希望这对您有所帮助,我还没有找到任何有效的示例,并且花了很多时间进行搜索和测试。
使用 pysftp 包装器的实现现在被视为从 2016 年起已停止使用。