SSH解釋
百度百科解釋:
SSH 爲 Secure Shell 的縮寫,由 IETF 的網絡小組(Network Working Group)所制定;SSH 爲建立在應用層基礎上的安全協議。SSH 是目前較可靠,專爲遠程登錄會話和其他網絡服務提供安全性的協議。利用 SSH 協議可以有效防止遠程管理過程中的信息泄露問題。SSH最初是UNIX系統上的一個程序,後來又迅速擴展到其他操作平臺。SSH在正確使用時可彌補網絡中的漏洞。SSH客戶端適用於多種平臺。幾乎所有UNIX平臺—包括HP-UX、Linux、AIX、Solaris、Digital UNIX、Irix,以及其他平臺,都可運行SSH。
傳統的網絡服務程序,如:ftp、pop和telnet在本質上都是不安全的,因爲它們在網絡上用明文傳送口令和數據,別有用心的人非常容易就可以截獲這些口令和數據。而且,這些服務程序的安全驗證方式也是有其弱點的, 就是很容易受到“中間人”(man-in-the-middle)這種方式的攻擊。所謂“中間人”的攻擊方式, 就是“中間人”冒充真正的服務器接收你傳給服務器的數據,然後再冒充你把數據傳給真正的服務器。服務器和你之間的數據傳送被“中間人”一轉手做了手腳之後,就會出現很嚴重的問題。通過使用SSH,你可以把所有傳輸的數據進行加密,這樣"中間人"這種攻擊方式就不可能實現了,而且也能夠防止DNS欺騙和IP欺騙。使用SSH,還有一個額外的好處就是傳輸的數據是經過壓縮的,所以可以加快傳輸的速度。SSH有很多功能,它既可以代替Telnet,又可以爲FTP、PoP、甚至爲PPP提供一個安全的"通道"
python中的SSH
Python中的paramiko包提供了便捷的ssh連接功能。官網連接如下,功能比較全,官方API解釋比較詳細。
http://www.paramiko.org/
Pickering的LXI設備提供使用SSH控制的方式,其開啓SSH服務的指導連接如下:
https://www.pickeringtest.com/zh-cn/kb/hardware-topics/lxi-ethernet-specific-pages/information-pickering-lxi-products/ssh-control-of-lxi-devices
其原理爲在ssh連上以後,系統會在shell中打開一個程序,用戶直接在面板中輸入相應的命令,實現對設備的控制。
常規的一個簡單的paramiko包的應用如下:
import paramiko
# 實例化SSHClient
client = paramiko.SSHClient()
# 自動添加策略,保存服務器的主機名和密鑰信息,如果不添加,那麼不再本地know_hosts文件中記錄的主機將無法連接
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 連接SSH服務端,以用戶名和密碼進行認證
client.connect(hostname='192.168.1.105', port=22, username='root', password='123456')
# 打開一個Channel並執行命令
stdin, stdout, stderr = client.exec_command('df -h ') # stdout 爲正確輸出,stderr爲錯誤輸出,同時是有1個變量有值
# 打印執行結果
print(stdout.read().decode('utf-8'))
# 關閉SSHClient
client.close()
但是在使用的過程中,發現提交命令後在stdout.read()這步程序會鎖住,沒辦法讀取到返回值。經過長時間的嘗試,是因爲在連接到設備後,設備開始執行設備控制程序,此時paramiko認爲命令一直在執行,所以一直在等到返回值,其通道沒有關閉,所以就卡在了read上邊。
經過思考,發現其實在連接設備以後,我們需要的並不是執行系統命令,而是只需要往shell中發送字符串就可以,於是有了接下來的程序,這個程序在連接到設備後,不是執行命令,而是建立一個channel,然後發送字符串和接收輸出。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Frank
import paramiko,time
class PiSSH():
def __init__(self,host:str='',port:int = 22,username:str = '',password:str = '',timeout:float =1.0):
'''
:param host:
:param port:
:param username:
:param password:
:param timeout: 該參數是連接ssh時的超時設置,單位爲秒
'''
self.host = host
self.port = port
self.username = username
self.password = password
self.timeout = timeout #該參數是連接ssh時的超時設置,單位爲秒
self.channel = None
self.ssh_client = None
self.read_recv_time_delay = 0.05 #發送指令後回讀的延時,若send函數的回讀值不完整適當調大該參數,單位是秒
def __new__(cls, *args, **kwargs):
'''
單例模式,保證只有一個連接
:param args:
:param kwargs:
:return:
'''
if not hasattr(PiSSH,'_instance'):
cls._instance = super(PiSSH, cls).__new__(cls)
return cls._instance
def _connect(self):
'''
連接sshhost,並且開啓一個shell的channel,用於信息的收發,相當於直接在遠程機上打開shell,
一般在實例化對象之後,只要不銷燬,就只會連接一次,若連接超時或者突然斷開連接會拋出異常
:return:
'''
if not self._connected():
self.ssh_client = paramiko.SSHClient()
self.ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy)
self.ssh_client.connect(hostname = self.host,
port = self.port,
username= self.username,
password = self.password,
timeout = self.timeout
)
self.channel = self.ssh_client.invoke_shell()
def _connected(self):
'''
檢測是否已連接
:return:
'''
if self.channel and self.ssh_client.get_transport():
if self.ssh_client.get_transport().is_active():
return True
else:
return False
return False
def send(self,command:str) -> str:
'''
發送指令,返回指令執行結果的字符串
:param command:
:return:
'''
self._connect()
self.channel.send(command+'\n')
time.sleep(self.read_recv_time_delay)
result =''
while self.channel.recv_ready():
result += self.channel.recv(1024).decode('utf-8')
return result
def __del__(self):
'''
銷燬的時候自動關閉連接
:return:
'''
if self._connected():
self.channel.close()
self.ssh_client.close()
使用這個類進行驗證:
from pissh import PiSSH
host = '169.254.217.14' #設置爲機箱IP
username = 'sshuser'
password = '123456' #需要開啓機箱的SSH功能,
port = 22
pi =PiSSH(host=host,port=port,username=username,password=password,timeout=1) #實例化
pi.read_recv_time_delay =0.05 #設置回讀延時,若回讀不完整可以調大,目前默認0.05秒,我在我的電腦上測試沒問題,默認就是0.05s
if __name__ == '__main__':
while True:
command = input('請輸入指令》》').strip().upper()
if command == 'Q':
break #按q退出
res = pi.send(command)
print(res)
可以正確的執行指令,測試成功