Paramiko简介
paramiko是Python实现SSHv2协议的模块,它支持口令认证和公钥认证两种方式,可以实现安全的远程命令执行、文件传输等。
Paramiko组件架构
最常用的两个类为:SSHClient类、SFTPClient类,分别同SSH和SFTP功能。
Paramiko常用类简介
Channel类
用于创建在SSH Transport上的安全通道。
包含执行命令,请求X11会话,发送数据,打开交互式会话等方法。通常这些来自Channel类的常用方法已包装在了SSHClient类中。
Message类
SSH Message是字节流。该类对字符串、整数、bools和无限精度整数(Python中称为long)的某些组合进行编码。
包含向流中写入字节,提取字节等方法。
Packetizer
数据包处理类,包含检查握手、获取channel ID等方法。
Transport类
用于在现有套接字或类套接字对象上创建一个Transport会话对象。
包含公钥认证,打开channel通道等方法。
SFTPClient类
通过一个打开的SSH Transport会话创建SFTP会话通道并执行远程文件操作。
包含文件上传,下载等方法。
SSHClient类
是与SSH服务器会话的高级表示。该类集成了Transport、Channel和SFTPClient类。
包含建立连接,打开交互式会话等方法。
注:由于SSHClient类集成了Transport、channel和SFTPClient类,上述方法都可由SSHClient这一个类实现,SSH会话更是如此。
Paramiko秘钥相关类简介
SSH Agent类
用于SSH代理。
Host keys类
与OpenSSH known_hosts文件相关,用于创建一个host keys对象。
OpenSSH把用户访问过每个计算机的公钥都记录在~/.ssh/known_hosts,当下次访问相同计算机时,会核对公钥,如果公钥不同OpenSSH会发出警告,避免用户受到中间人攻击等。通常客户端第一次连接SSH服务器均需要输入yes或no进行确认。
Key handling类
用于创建对应秘钥类型的实例,如RSA秘钥、DSS/DSA秘钥。
Paramiko使用流程图
Transport类及其方法介绍
一个SSH Transport连接到一个流(通常为套接字),协商加密会话,进行认证。后续可在加密会话上创建通道,多个通道可以在单个会话中多路复用。
import paramiko
tran=paramiko.Transport(('192.168.56.100',22)) # 建立Transport对象,实例化SSH会话通道
tran.connect(username='client',password='test') # 建立SSH会话连接,并使用密码或私钥进行身份认证
close() # 关闭会话
Key handling类及其方法介绍
用于创建对应密钥类型的实例,如RSA秘钥,DSS(DSA)密钥。这个类包含了密钥的读取、写入等相关方法。
常用方法
- RSAKey.from_private_key_file(filename) 从文件读取RSA私钥来创建密钥对象。
- DSSKey.from_private_key_file(filename) 从文件读取DSA私钥来创建密钥对象。
示例
key=paramiko.RSAKey.from_private_key_file(r'C:\Users\exampleuser\.ssh\id_rsa')
SFTPClient类及其方法介绍
通过一个打开的SSH Transport会话通道创建SFTP会话连接并执行远程文件操作。
常用方法
- from_transport() :从打开的Transport创建一个SFTP会话连接。
-
windows_size:可选参数,SFTP会话窗口大小 。
-
max_packet_size:可选参数,SFTP会话最大数据包大小。
- get() :下载指定文件。
-
remotepath:远程文件。
-
localpath:本地主机的目的路径,该路径应包含文件名(仅指定目录可能会导致错误)。
- put() :上传指定文件。
-
与get()方法同理。
示例
import paramiko
key=paramiko.RSAKey.from_private_key_file(r'C:\Users\exampleuser\.ssh\id_rsa')
tran=paramiko.Transport(('192.168.56.100',22))
tran.connect(username='client',pkey=key)
sftp=paramiko.SFTPClient.from_transport(tran,window_size=None,max_packet_size=None)
local_path=r'C:\Users\exampleuser\.ssh\vrptest.cfg'
remote_path='/vrpcfg.cfg'
sftp.get(remote_path,local_path)
sftp.put(local_path,remotepath)
SSHClient类及其方法介绍
该类已经包装了Transport类、Channel类和SFTPClient类来进行会话通道的建立和鉴权认证。
常用方法
connect():实现远程服务器的连接与认证。
client.connect(hostname='192.168.56.100',port=22,username='client',key_filename='id_rsa')
client.connect(hostname='192.168.56.100',port=22,username='client',password='123456')
-
hostname:连接的目标主机(必选参数,其余参数都有默认值)。
-
port:指定端口,默认22。
-
username:进行认证的用户名,默认为空。
-
password:进行认证的用户密码,默认为空。
-
key_filename:一个文件名或文件列表,指定私钥,默认为空。
-
pkey:用于身份验证的私钥。
set_missing_host_key_policy():设置连接到没有已知主机密钥的服务器时使用的策略。
client.set_missing_host_key_policy(paramiko.client.AutoAddPolicy())
-
AutoAddPolicy:自动添加主机名及主机密钥到本地HostKey对象,不依赖load_system_host_key的配置。即新建立ssh连接时不需要再输入yes或no进行确认 。
-
WarningPolicy:用于记录一个未知的主机密钥的Python警告并接受,功能上和AutoAddPolicy类似,但是会提示时新连接。
-
RejectPolicy:自动拒绝未知的主机名和密钥,依赖load_system_host_key的配置(默认选项)。
load_system_host_keys():从系统文件中加载主机密钥(默认为空):
client.load_system_host_keys()
- filename:文件名,默认为空。如果没有参数,则尝试从用户本地的“known_hosts”文件中读取密钥信息。
exec_command():在远程服务器执行Linux命令。
stdin,stdout,stderr=client.exec_command('ls -l')
invoke_shell():在远程服务器上启动交互式shell会话。
cli=client.invoke_shell()
open_sftp():在一个会话连接中创建SFTP通道。
sftp=client.open_sftp()
close():关闭连接。
SSH Python脚本实践
示例1:连接ubuntu24.04虚拟机执行命令并回显结果。
import paramiko
import time
ssh=paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='192.168.100.140', username='root', password='123456')
# cmd='date;ls -l; uname -a' # 将需要执行的命令以分号隔开并赋给cmd
# stdin, stdout, stderr = ssh.exec_command(cmd)
stdin, stdout, stderr = ssh.exec_command('date;ls -l;uname -r')
print(stdout.read().decode())
ssh.close()
输出结果如下
"D:\Program Files\Python312\python.exe" C:\Users\xiaoqi\PycharmProjects\learning\ssh2.py
2024年 06月 05日 星期三 11:02:53 CST #### 第一条date命令执行结果
总计 44
drwxr-xr-x 2 hcie17088 hcie17088 4096 4月 27 11:47 公共
drwxr-xr-x 2 hcie17088 hcie17088 4096 4月 27 11:47 模板
drwxr-xr-x 2 hcie17088 hcie17088 4096 4月 27 11:47 视频
drwxr-xr-x 2 hcie17088 hcie17088 4096 4月 27 11:47 图片
drwxr-xr-x 2 hcie17088 hcie17088 4096 4月 27 11:47 文档
drwxr-xr-x 2 hcie17088 hcie17088 4096 4月 27 11:47 下载
drwxr-xr-x 2 hcie17088 hcie17088 4096 4月 27 11:47 音乐
drwxr-xr-x 2 hcie17088 hcie17088 4096 6月 3 15:48 桌面
drwxrwxr-x 2 hcie17088 hcie17088 4096 6月 4 10:50 learning_python
drwxrwxr-x 4 hcie17088 hcie17088 4096 6月 3 16:32 mysite
drwx------ 6 hcie17088 hcie17088 4096 6月 3 16:12 snap
6.8.0-31-generic # 最后一条uname -r命令执行结果
示例:exec_command和invoke_shell区别
exec_command()函数是将服务器执行完的结果一次性返回给你,发送完指令,连接就会断开。使用SSH exec channel。
invoke_shell()函数类似shell终端,长连接,保持状态。使用SSH shell cannel。
import paramiko
ssh=paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='192.168.100.140', username='root', password='123456')
while True:
cmdline=input("command:")
if cmdline=='exit':
break
stdin, stdout, stderr = ssh.exec_command(cmdline)
for row in stdout.readlines():
row=row.replace('\r','').replace('\n','').replace('\t','') # 替换空格、制表符
print(row)
import paramiko
trans=paramiko.Transport(('192.168.100.140', 22))
trans.start_client() # 启动一个客户端
trans.auth_password(username='root', password='123456')
channel=trans.open_session() # 打开一个通道
channel.get_pty() # 获取终端
channel.invoke_shell() # 激活终端,类似于xshell登录系统一样
results=channel.recv(1024000)
print(f"输出1:{results.decode()}")
channel.send("ll\n")
while True:
results2=channel.recv(1024000)
print(f"输出2:{results2.decode()}")
import paramiko,time # 导入模块
ssh=paramiko.SSHClient() # 实例化SSH对象
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 允许连接未知主机
ssh.connect(hostname='192.168.46.100',port=22,username='client',key_filename=r'C:\Users\exampleuser\.ssh\id_rsa') # 建立SSH会话连接
cli=ssh.invoke_shell() # 打开交互式会话
cil.send('screen-length 0 temporary\n') # 发生取消分屏命令
cli.send('display cu\n') # 发生显示当前配置命令
time.sleep(3) # 设置暂定3秒
dis_cu=cli.recv(999999).decode() # 实例化接收的数据
print(dis_cu) # 打印回显
ssh.close() # 关闭SSH连接