Paramiko 的 SSHClient 与 SFTP

发布于 2024-09-17 17:45:53 字数 180 浏览 4 评论 0原文

如何通过远程服务器上的 SSHClient 进行 SFTP 传输?我有一个本地主机和两个远程主机。远程主机是备份服务器和Web服务器。我需要在备份服务器上找到必要的备份文件,并通过 SFTP 将其放在 Web 服务器上。如何使 Paramiko 的 SFTP 传输与 Paramiko 的 SSHClient 配合使用?

How I can make SFTP transport through SSHClient on the remote server? I have a local host and two remote hosts. Remote hosts are backup server and web server. I need to find on backup server necessary backup file and put it on web server over SFTP. How can I make Paramiko's SFTP transport work with Paramiko's SSHClient?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

逆光下的微笑 2024-09-24 17:45:53

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()

paramiko.SFTPClient

Sample Usage:

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()
别靠近我心 2024-09-24 17:45:53

接受的答案“有效”。但由于使用了低级 Transport 类,它绕过了主机密钥验证,这是一个安全缺陷,因为它使代码容易受到 中间人攻击

更好的是使用正确的 Paramiko SSH API,即 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“未知服务器”

The accepted answer "works". But with its use of the low-level Transport class, it bypasses a host key verification, what is a security flaw, as it makes the code susceptible to Man-in-the-middle attacks.

Better is to use the right Paramiko SSH API, the SSHClient, which does verify the host key:

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)

For details about verifying the host key, see:
Paramiko "Unknown Server"

凉世弥音 2024-09-24 17:45:53

如果您有 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
...

If you have a SSHClient, you can also use 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
...
要走就滚别墨迹 2024-09-24 17:45:53

除了第一个答案(很好但取决于用户名/密码)之外,以下内容还显示了如何使用 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='.')

In addition to the first answer which is great but depends on username/password, the following shows how to use an ssh key:

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='.')
逆蝶 2024-09-24 17:45:53

对于那些需要与需要私钥的 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()

请注意,只有 classic < 中的证书支持 a href="https://stackoverflow.com/a/57157401">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>

为了避免 man in对于中间攻击,重要的是不要使用 paramiko.AutoAddPolicy() 并按上述方式以编程方式加载公共主机密钥或从 ~/.ssh/known_hosts< br>
文件的格式必须为 "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

上面的代码适用于与 GoAnywhere 的 SFTP 集成。

我希望这对您有所帮助,我还没有找到任何有效的示例,并且花了很多时间进行搜索和测试。
使用 pysftp 包装器的实现现在被视为从 2016 年起已停止。

For those anyone need to integrate with an ssh/sftp server that requires a private key and want to perform host key verification for the known host by using a specific public key, here is a snippet code with 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()

Notice that only certificates in classic Openssh format are supported, otherwise needs to be converted with the following commands (also for the latest Openssh formats):

$chmod 400 /path/to/private_key_file.pvt
$ssh-keygen -p -f /path/to/private_key_file.pvt -m pem -P <currentPassphrase> -N <newPassphrase>

In order to avoid man in the middle attack, it is important to do not use paramiko.AutoAddPolicy() and load the public host key programmatically as above or load it from ~/.ssh/known_hosts
The file must be in the format "<host_name> ssh-rsa AAAAB3NzaC1yc2EAAAA..."
In case you don't have the public key and you trust the target host (take care to mitm), you can download it using $ssh-keyscan target.hostname.com command.

The above code is the only way I found to avoid the following error during connection:

paramiko.ssh_exception.SSHException: Server 'x.y.z' not found in known_hosts

This error was prompted also with the following way to load the public certificates:

key = paramiko.RSAKey(data=decodebytes(sftp_public_key))
ssh_client.get_host_keys().add(sftp_hostname, 'ssh-rsa', key)

Also the following code was not able for me to load the certificate (tried also by encoding the certificate in 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)

It always ends with:

  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

The above code above worked for the SFTP integration with GoAnywhere.

I hope this is helpful, I've not found any working example and spent many hours in searches and tests.
The implementations using pysftp wrapper it is now to be considered as discontinued from 2016.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文