Heim > Artikel > Betrieb und Instandhaltung > Grundlegende Einführung in SSH und SSH-Dienste (einschließlich Tunnelinhalt)
1.1 Grundkenntnisse der asymmetrischen Verschlüsselung
Symmetrische Verschlüsselung: Verschlüsselung und Entschlüsselung verwenden denselben Algorithmus, sofern eine Entschlüsselung bereitgestellt wird mit Verschlüsselung Die Entschlüsselung kann mit einem konsistenten Passwort durchgeführt werden. Zum Beispiel QQ-Login-Passwort, Bankkarten-Passwort, stellen Sie einfach sicher, dass das Passwort korrekt ist.
Asymmetrische Verschlüsselung: Verschlüsseln und Entschlüsseln mit öffentlichem und privatem Schlüssel. Mit dem öffentlichen Schlüssel verschlüsselte Inhalte können mit dem privaten Schlüssel entschlüsselt werden, und mit dem privaten Schlüssel verschlüsselte Inhalte können mit dem öffentlichen Schlüssel entschlüsselt werden. Im Allgemeinen werden die Verschlüsselung mit öffentlichem Schlüssel und die Entschlüsselung mit privatem Schlüssel verwendet, dies ist jedoch nicht unbedingt der Fall. Wenn eine Zertifizierungsstelle beispielsweise ein Zertifikat signiert, verwendet sie ihren eigenen privaten Schlüssel zur Verschlüsselung. Im als nächstes vorgestellten SSH-Dienst wird zwar immer empfohlen, öffentliche Schlüssel zu verteilen, private Schlüssel können jedoch auch verteilt werden.
Wenn also A (privater Schlüssel A, öffentlicher Schlüssel A) und B (privater Schlüssel B, öffentlicher Schlüssel B) generiert, dann umfasst die asymmetrische Verschlüsselungssitzungssituation zwischen A und B Folgendes:
(1).A verteilt seinen öffentlichen Schlüssel A an B, B verschlüsselt die Daten mit dem öffentlichen Schlüssel A und sendet die verschlüsselten Daten an A. A verwendet seinen privaten Schlüssel A, um die Daten zu entschlüsseln.
(2).A verteilt seinen öffentlichen Schlüssel A an B und verwendet seinen eigenen privaten Schlüssel A, um Daten zu verschlüsseln, und dann verwendet B öffentlichen Schlüssel A, um die Daten zu entschlüsseln.
(3).B verteilt seinen öffentlichen Schlüssel B an A. A nimmt den öffentlichen Schlüssel B, um die Daten zu verschlüsseln, und sendet die verschlüsselten Daten an B. B wird seinen privaten Schlüssel B verwenden, um die Daten zu entschlüsseln.
(4).B verteilt seinen öffentlichen Schlüssel B an A und verwendet seinen eigenen privaten Schlüssel B, um Daten zu verschlüsseln, und dann verwendet A den öffentlichen Schlüssel B, um die Daten zu entschlüsseln.
Obwohl theoretisch vier Szenarien unterstützt werden, unterstützt SSH während der Authentifizierungsphase von SSH nur, dass der Server den öffentlichen Schlüssel und der Client den privaten Schlüssel behält , So Es gibt nur zwei Möglichkeiten: Der Client generiert ein Schlüsselpaar und verteilt den öffentlichen Schlüssel an den Server. Der Server generiert ein Schlüsselpaar und verteilt den privaten Schlüssel an den Client. Aus Sicherheits- und Komfortgründen generiert der Client jedoch im Allgemeinen das Schlüsselpaar und verteilt den öffentlichen Schlüssel. Beispiele für diese beiden Verteilungsmethoden sind unten aufgeführt.
(1). SSH ist ein Sicherheitsprotokoll auf der Transportschicht und der Anwendungsschicht. Es kann die Sicherheit der Verbindung nur durch Verschlüsselung der Sitzungen zwischen den beiden Parteien gewährleisten. Wenn die SSH-Verbindung erfolgreich ist, wird eine Sitzung zwischen dem Client und dem Server aufgebaut. Die Sitzung wird verschlüsselt und alle nachfolgenden Kommunikationen zwischen dem Client und dem Server werden über die Sitzung übertragen.
(2). Der Daemon-Prozess des SSH-Dienstes ist sshd, der standardmäßig Port 22 überwacht.
(3). Alle SSH-Client-Tools, einschließlich SSH-Befehle, SCP, SFTP, SSH-Copy-ID und andere Befehle, sind zur Erledigung von Aufgaben auf SSH-Verbindungen angewiesen. Das heißt, sie sind alle mit Port 22 des Servers verbunden, aber nach der Verbindung werden die relevanten auszuführenden Befehle konvertiert und zur Ausführung durch den Remote-Host an den Remote-Host übertragen.
(4) Der .ssh-Client-Befehl (ssh, scp, sftp usw.) liest zwei Konfigurationsdateien: die globale Konfigurationsdatei /etc/ssh/ssh_config und die Benutzerkonfigurationsdatei ~/.ssh/config . Tatsächlich können Konfigurationsoptionen auch auf der Befehlszeile übergeben werden. Die Priorität, die sie in Kraft setzen, ist: Befehlszeilenkonfigurationsoptionen > ~/.ssh/config >
(5).ssh umfasst zwei Überprüfungen: Host-Überprüfung und Benutzerauthentifizierung. Durch die Host-Verifizierung und dann durch die Benutzer-Verifizierung auf dem Host kann die Identität des Benutzers eindeutig bestimmt werden. Auf einem Host können viele Benutzer vorhanden sein, sodass jeder Host nur einmal authentifiziert werden muss, jeder Benutzer auf dem Host jedoch einzeln authentifiziert werden muss.
(6).ssh unterstützt mehrere Authentifizierungsmechanismen, die am häufigsten verwendeten sind der Passwortauthentifizierungsmechanismus und der Authentifizierungsmechanismus mit öffentlichem Schlüssel. Der Authentifizierungsmechanismus mit öffentlichem Schlüssel ist in einigen Szenarien fast notwendig, um gegenseitiges Vertrauen zwischen zwei Maschinen zu erreichen. Obwohl die beiden oben genannten Authentifizierungsmechanismen häufig verwendet werden, ist die Standardreihenfolge bei der Authentifizierung gssapi-with-mic, hostbased, publickey, Keyboard-interactive, Password. Beachten Sie, dass der Host-Authentifizierungsmechanismus hostbasiert keine Host-Authentifizierung ist (die gelesene Authentifizierungsdatei ist /etc/hosts.equiv oder /etc/shosts.equiv) und daher selten im Netzwerk zu sehen ist . Im Allgemeinen kann das Ändern der Authentifizierungsreihenfolge mithilfe des Befehls „PreferredAuthentications“ in der SSH-Konfigurationsdatei (nicht in der SSH-Konfigurationsdatei) als eine Möglichkeit angesehen werden, die Effizienz der Überprüfung zu verbessern.
(7) Der SSH-Client verfügt tatsächlich über viele leistungsstarke Funktionen, wie z. B. Portweiterleitung (Tunnelmodus), Proxy-Authentifizierung, Verbindungsfreigabe (Verbindungsmultiplexing) usw.
(8). Die SSH-Serverkonfigurationsdatei ist /etc/ssh/sshd_config. Beachten Sie, dass sie sich von der globalen Konfigurationsdatei /etc/ssh/ssh_config unterscheidet.
(9). Der wichtigste Punkt ist, dass SSH beim Anmelden die Zuweisung eines Pseudo-Terminals anfordert . Allerdings können einige Authentifizierungsprogramme wie sudo diese Art der Terminalzuweisung verbieten, was dazu führen kann, dass die SSH-Verbindung fehlschlägt. Wenn Sie beispielsweise ssh verwenden, um den sudo-Befehl auszuführen, prüft sudo, ob Sie ssh ein Terminal zuweisen möchten.
Wenn Sie eine Verbindung von Client A (172.16.10.5) zu Server B (172.16.10.6) herstellen, wird Folgendes angezeigt: Zwei Prozesse der Host-Authentifizierung und der Benutzeridentitätsauthentifizierung nehmen als Beispiel den asymmetrischen RSA-Verschlüsselungsalgorithmus.
[root@xuexi ~]# ssh 172.16.10.6
Das SSHD-Dienstprogramm wird zunächst auf Server B gestartet, d. h. der SSH-Dienst wird aktiviert und Port 22 geöffnet (Standard).
Wenn Client A eine Verbindung zu B herstellen möchte, führt er zunächst einen Host-Überprüfungsprozess durch, d. h. ermittelt, ob Host B hat jemals eine Verbindung hergestellt.
Die Methode zur Bestimmung besteht darin, die Datei ~/.ssh/known_hosts und die Datei /etc/ssh/known_hosts zu lesen und nach den Hostinformationen von 172.16.10.6 (dem Host) zu suchen Diese Informationen werden als Host-Schlüssel bezeichnet und geben die Host-Identität an. Wenn der der Adresse entsprechende Hostschlüssel nicht gefunden wird, fragen Sie, ob der von Host B gesendete Hostschlüssel gespeichert werden soll. Wenn der Hostschlüssel der Adresse gefunden wird, vergleichen Sie den Hostschlüssel mit dem von Host B gesendeten Hostschlüssel. Wenn ja Sind genau gleich, bedeutet dies, dass Host A den Hostschlüssel von Host B zuvor gespeichert hat. Es besteht keine Notwendigkeit, ihn erneut zu speichern, und es wird direkt mit dem nächsten Prozess fortgefahren – der Authentifizierung Sie werden gefragt, ob der derzeit von Host B verwendete Hostschlüssel gespeichert werden soll.
Der Prozess der Abfrage, ob der Hostschlüssel gespeichert werden soll, ist wie folgt:
[root@xuexi ~]# ssh 172.16.10.6 The authenticity of host '172.16.10.6 (172.16.10.6)' can't be established.RSA key fingerprint is f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf. Are you sure you want to continue connecting (yes/no)? yes
Oder verwenden Sie den Grafische Oberfläche unter Windows Bei Verwendung des SSH-Client-Tools:
Bevor wir den Authentifizierungsprozess erklären, werfen wir einen Blick auf das Format der Datei „known_hosts“. Nehmen Sie als Beispiel ~/.ssh/known_hosts.
[root@xuexi ~]# cat ~/.ssh/known_hosts172.16.10.6 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC675dv1w+GDYViXxqlTspUHsQjargFPSnR9nEqCyUgm5/32jXAA3XTJ4LUGcDHBuQ3p3spW/eO5hAP9eeTv5HQzTSlykwsu9He9w3ee+TV0JjBFulfBR0weLE4ut0PurPMbthE7jIn7FVDoLqc6o64WvN8LXssPDr8WcwvARmwE7pYudmhnBIMPV/q8iLMKfquREbhdtGLzJRL9DrnO9NNKB/EeEC56GY2t76p9ThOB6ES6e/87co2HjswLGTWmPpiqY8K/LA0LbVvqRrQ05+vNoNIdEfk4MXRn/IhwAh6j46oGelMxeTaXYC+r2kVELV0EvYV/wMa8QHbFPSM6nLz
In dieser Datei hat jede Zeile einen Hostschlüssel und am Anfang der Zeile steht der Hostname, der bei der Suche nach Hostschlüsselindex , der Inhalt nach dem Hostnamen ist der Hostschlüsselteil. Am Beispiel dieser Datei zeigt sie, dass Client A einmal versucht hat, eine Verbindung zu Host B unter 172.16.10.6 herzustellen, und den Hostschlüssel von Host B gespeichert hat. Wenn er das nächste Mal eine Verbindung zu Host B herstellt, sucht er nach dem Hostschlüssel von Host B und vergleichen Sie den von 10.6 gesendeten Hostschlüssel. Wenn er übereinstimmt, bedeutet dies, dass der Hostschlüssel tatsächlich der Hostschlüssel ist, der derzeit von 172.16.10.6 verwendet wird Der Hostschlüssel oder der Hostschlüssel in dieser Datei wurde geändert. Der Hostschlüssel wurde geändert.
Wo ist also der aktuell von Host B verwendete Hostschlüssel gespeichert? In der Datei /etc/ssh/ssh_host* werden diese Dateien neu erstellt, wenn das sshd-Dienstprogramm des Servers (hier Host B) startet. Am Beispiel des RSA-Algorithmus wird dieser in /etc/ssh/ssh_host_rsa_key und /etc/ssh/ssh_host_rsa_key.pub gespeichert. Die öffentliche Schlüsseldatei /etc/ssh/ssh_host_rsa_key.pub speichert den Hostschlüssel.[root@xuexi ~]# cat /etc/ssh/ssh_host_rsa_key.pub # 在主机B上查看ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC675dv1w+GDYViXxqlTspUHsQjargFPSnR9nEqCyUgm5/32jXAA3XTJ4LUGcDHBuQ3p3spW/eO5hAP9eeTv5HQzTSlykwsu9He9w3ee+TV0JjBFulfBR0weLE4ut0PurPMbthE7jIn7FVDoLqc6o64WvN8LXssPDr8WcwvARmwE7pYudmhnBIMPV/q8iLMKfquREbhdtGLzJRL9DrnO9NNKB/EeEC56GY2t76p9ThOB6ES6e/87co2HjswLGTWmPpiqY8K/LA0LbVvqRrQ05+vNoNIdEfk4MXRn/IhwAh6j46oGelMxeTaXYC+r2kVELV0EvYV/wMa8QHbFPSM6nLz
Während der Host-Verifizierungsphase hält der Server den privaten Schlüssel und der Client den öffentlichen Schlüssel vom Server. Beachten Sie, dass dies das Gegenteil davon ist, wer während der Authentifizierungsphase den Schlüssel besitzt.
Eigentlich vergleicht SSH den Host-Schlüssel nicht direkt, da der Host-Schlüssel zu lang ist und die Vergleichseffizienz gering ist. SSH wandelt also den Host-Schlüssel in einen Host-Schlüssel-Fingerabdruck um und vergleicht dann die Host-Schlüssel-Fingerabdrücke auf beiden Seiten. Das Fingerabdruckformat ist wie folgt:[root@xuexi ~]# ssh 172.16.10.6 The authenticity of host '172.16.10.6 (172.16.10.6)' can't be established.RSA key fingerprint is f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf. Are you sure you want to continue connecting (yes/no)? yes
[root@xuexi ~]# ssh-keygen -l -f ~/.ssh/known_hosts2048 f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf 172.16.10.6 (RSA) [root@xuexi ~]# ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key2048 f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf (RSA)
[root@xuexi ~]# ssh-keygen -lv -f ~/.ssh/known_hosts2048 f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf 172.16.10.6 (RSA)+--[ RSA 2048]----+ | | | | | . | | o | | S. . + | | . +++ + . | | B.+.= . | | + B. +. | | o.+. oE | +-----------------+
主机验证通过后,将进入身份验证阶段。SSH支持多种身份验证机制,它们的验证顺序如下:gssapi-with-mic,hostbased,publickey,keyboard-interactive,password,但常见的是密码认证机制(password)和公钥认证机制(public key)。当公钥认证机制未通过时,再进行密码认证机制的验证。这些认证顺序可以通过ssh配置文件(注意,不是sshd的配置文件)中的指令PreferredAuthentications改变。
如果使用公钥认证机制,客户端A需要将自己生成的公钥(~/.ssh/id_rsa.pub)发送到服务端B的~/.ssh/authorized_keys文件中。当进行公钥认证时,客户端将告诉服务端要使用哪个密钥对,并告诉服务端它已经访问过密钥对的私钥部分~/.ssh/id_rsa(不能直接提供给服务端匹配检测,因为私钥不能泄露),然后服务端将检测密钥对的公钥部分,判断该客户端是否允许通过认证。如果认证不通过,则进入下一个认证机制,以密码认证机制为例。
当使用密码认证时,将提示输入要连接的远程用户的密码,输入正确则验证通过。
当主机验证和身份验证都通过后,分两种情况:直接登录或执行ssh命令行中给定某个命令。如:
[root@xuexi ~]# ssh 172.16.10.6 [root@xuexi ~]# ssh 172.16.10.6 'echo "haha"'
(1). Die ehemalige SSH-Befehlszeile enthält keine Befehlsparameter, was bedeutet, dass ein Benutzer auf dem Remote-Host (hier der Root-Benutzer) verwendet wird, um sich beim Remote-Host 172.16.10.6 anzumelden, also dem Remote-Host Der Host weist ein Pseudo-Terminal zu und betritt die Bash-Umgebung.
(2). Die letztgenannte SSH-Befehlszeile verfügt über Befehlsparameter, was bedeutet, dass der angegebene Befehl [echo „haha“] auf dem Remote-Host ausgeführt wird. Remote-Befehle auf der SSH-Befehlszeile werden über den von fork ssh-agent erhaltenen untergeordneten Prozess ausgeführt. Wenn der Befehl ausgeführt wird, verschwindet der untergeordnete Prozess, ssh wird ebenfalls beendet und die eingerichteten Sitzungen und Verbindungen werden ebenfalls geschlossen. (Der Grund, warum wir den Ausführungsprozess von Remote-Befehlen hier klar erläutern müssen, besteht darin, die Vorsichtsmaßnahmen bei der Implementierung der Portweiterleitung mit SSH zu erläutern, die später eingeführt werden.)
Nach erfolgreicher SSH-Verbindung wird tatsächlich protokolliert in der Befehlszeile eingeben oder ausführen Bevor Sie den Befehl eingeben, können Sie den Befehl angeben, der remote ausgeführt werden soll. Mit anderen Worten, das erste, was Sie tun müssen Nachdem die SSH-Verbindung hergestellt wurde, müssen Sie den Befehl remote ausführen. Führen Sie die Befehle in diesen beiden Dateien auf dem Host aus.
Nehmen Sie als Beispiel Host A, der eine Verbindung zu Host B herstellt, und Host B ist ein SSH-Server .
Auf dem Server, Host B:
/etc/ssh/sshd_config: SSH-Dienstprogramm SSHD-Konfigurationsdatei .
/etc/ssh/ssh_host_*: Die öffentlichen Schlüssel- und privaten Schlüsseldateien des Servers, die beim Start des Dienstprogramms sshd generiert werden. Wie ssh_host_rsa_key und ssh_host_rsa_key.pub.
Die strengen Anforderungen der privaten Schlüsseldatei sind 600. Ist dies nicht der Fall, verweigert der SSHD-Dienst möglicherweise den Start.
Auf dem Client Host A:
Für diese Datei sind unbedingt Berechtigungen erforderlich.
Die Datei wird einfach ignoriert werden.
~/.ssh/id_rsa.pub: Der gepaarte öffentliche Schlüssel des privaten Schlüssels id_rsa. Unempfindlich gegenüber Berechtigungen. Bei Verwendung des Authentifizierungsmechanismus mit öffentlichem Schlüssel muss der Inhalt dieser Datei in die Datei
~/.ssh/RC: Die Befehlsliste wird gespeichert, sobald die SSH-Verbindung zum Remote-Host erfolgreich ist 🎜>: Beginnen Sie mit der Anmeldung oder der Ausführung von Befehlen in der SSH-Befehlszeile.
1.5 Kurze Einführung in Konfigurationsdateien
虽然服务端和客户端配置文件默认已配置项虽然非常少非常简单,但它们可配置项非常多。sshd_config完整配置项参见金步国翻译的sshd_config中文手册,ssh_config也可以参考sshd_config的配置,它们大部分配置项所描述的内容是相同的。
简单介绍下该文件中比较常见的指令。
[root@xuexi ~]# /etc//. # 监听的IP地址。. protocol version /etc//ssh_host_key # SSH 1保存位置/etc// protocol version /etc//ssh_host_rsa_key # SSH 2保存RSA位置/etc///etc//ssh_host_dsa_key # SSH 2保存DSA位置/etc///var/run//var/log//
一般来说,如非有特殊需求,只需修改下监听端口和UseDNS为no以加快主机验证阶段的速度即可。
配置好后直接重启启动sshd服务即可。
[root@xuexi ~]# service sshd restart
需要说明的是,客户端配置文件有很多配置项和服务端配置项名称相同,但它们一个是在连接时采取的配置(客户端配置文件),一个是sshd启动时开关性的设置(服务端配置文件)。例如,两配置文件都有GSSAPIAuthentication项,在客户端将其设置为no,表示连接时将直接跳过该身份验证机制,而在服务端设置为no则表示sshd启动时不开启GSSAPI身份验证的机制。即使客户端使用了GSSAPI认证机制,只要服务端没有开启,就绝对不可能认证通过。
下面也简单介绍该文件。
# Host * # Host指令是ssh_config中最重要的指令,只有ssh连接的目标主机名能匹配此处给定模式时, # 下面一系列配置项直到出现下一个Host指令才对此次连接生效 # ForwardAgent no # ForwardX11 no # RhostsRSAAuthentication no # RSAAuthentication yes # PasswordAuthentication yes # 是否启用基于密码的身份认证机制 # HostbasedAuthentication no # 是否启用基于主机的身份认证机制 # GSSAPIAuthentication no # 是否启用基于GSSAPI的身份认证机制 # GSSAPIDelegateCredentials no # GSSAPIKeyExchange no # GSSAPITrustDNS no # BatchMode no # 如果设置为"yes",将禁止passphrase/password询问。比较适用于在那些不需要询问提供密 # 码的脚本或批处理任务任务中。默认为"no"。 # CheckHostIP yes # AddressFamily any # ConnectTimeout 0# StrictHostKeyChecking ask # 设置为"yes",ssh将从不自动添加host key到~/.ssh/known_hosts文件, # 且拒绝连接那些未知的主机(即未保存host key的主机或host key已改变的主机)。 # 它将强制用户手动添加host key到~/.ssh/known_hosts中。 # 设置为ask将询问是否保存到~/.ssh/known_hosts文件。 # 设置为no将自动添加到~/.ssh/known_hosts文件。 # IdentityFile ~/.ssh/identity # ssh v1版使用的私钥文件 # IdentityFile ~/.ssh/id_rsa # ssh v2使用的rsa算法的私钥文件 # IdentityFile ~/.ssh/id_dsa # ssh v2使用的dsa算法的私钥文件 # Port 22 # 当命令行中不指定端口时,默认连接的远程主机上的端口 # Protocol 2,1# Cipher 3des # 指定ssh v1版本中加密会话时使用的加密协议 # Ciphers aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc # 指定ssh v1版本中加密会话时使用的加密协议 # MACs hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160 # EscapeChar ~# Tunnel no # TunnelDevice any:any # PermitLocalCommand no # 功能等价于~/.ssh/rc,表示是否允许ssh连接成功后在本地执行LocalCommand指令指定的命令。 # LocalCommand # 指定连接成功后要在本地执行的命令列表,当PermitLocalCommand设置为no时将自动忽略该配置 # %d表本地用户家目录,%h表示远程主机名,%l表示本地主机名,%n表示命令行上提供的主机名, # p%表示远程ssh端口,r%表示远程用户名,u%表示本地用户名。 # VisualHostKey no # 是否开启主机验证阶段时host key的图形化指纹 Host *GSSAPIAuthentication yes
如非有特殊需求,ssh客户端配置文件一般只需修改下GSSAPIAuthentication的值为no来改善下用户验证的速度即可,另外在有非交互需求时,将StrictHostKeyChecking设置为no以让主机自动添加host key。
此处先介绍ssh命令的部分功能,其他包括端口转发的在后文相关内容中解释,关于连接复用的选项本文不做解释。
语法:
ssh [options] [user@]hostname [command] 参数说明:-b bind_address :在本地主机上绑定用于ssh连接的地址,当系统有多个ip时才生效。-E log_file :将debug日志写入到log_file中,而不是默认的标准错误输出stderr。-F configfile :指定用户配置文件,默认为~/.ssh/config。-f :请求ssh在工作在后台模式。该选项隐含了"-n"选项,所以标准输入将变为/dev/null。-i identity_file:指定公钥认证时要读取的私钥文件。默认为~/.ssh/id_rsa。-l login_name :指定登录在远程机器上的用户名。也可以在全局配置文件中设置。-N :显式指明ssh不执行远程命令。一般用于端口转发,见后文端口转发的示例分析。-n :将/dev/null作为标准输入stdin,可以防止从标准输入中读取内容。ssh在后台运行时默认该项。-p port :指定要连接远程主机上哪个端口,也可在全局配置文件中指定默认的连接端口。-q :静默模式。大多数警告信息将不输出。-T :禁止为ssh分配伪终端。-t :强制分配伪终端,重复使用该选项"-tt"将进一步强制。-v :详细模式,将输出debug消息,可用于调试。"-vvv"可更详细。-V :显示版本号并退出。-o :指定额外选项,选项非常多。 user@hostname :指定ssh以远程主机hostname上的用户user连接到的远程主机上,若省略user部分,则表示使用本地当前用户。 :如果在hostname上不存在user用户,则连接将失败(将不断进行身份验证)。 command :要在远程主机上执行的命令。指定该参数时,ssh的行为将不再是登录,而是执行命令,命令执行完毕时ssh连接就关闭。
例如,以172.16.10.6主机上的longshuai用户登录172.16.10.6。
[root@xuexi ~]# ssh longshuai@172.16.10.6The authenticity of host '172.16.10.6 (172.16.10.6)' can't be established.ECDSA key fingerprint is 18:d1:28:1b:99:3b:db:20:c7:68:0a:f8:9e:43:e8:b4.Are you sure you want to continue connecting (yes/no)? yes # 主机验证Warning: Permanently added '172.16.10.6' (ECDSA) to the list of known hosts.longshuai@172.16.10.6's password: # 用户验证Last login: Wed Jul 5 12:27:29 2017 from 172.16.10.6
此时已经登录到了172.16.10.6主机上。
[longshuai@xuexi ~]$ hostname -I172.16.10.6
要退出ssh登录,使用logout命令或exit命令即可返回到原主机环境。
使用ssh还可以实现主机跳转,即跳板功能。例如主机B能和A、C通信,但A、C之间不同通信,即A71fb34173e4ee87dab1f85dc1c283a44B71fb34173e4ee87dab1f85dc1c283a44Cfe36de6936ad20bec13da33b00c99495A的情形。如果要从A登陆到C,则可以借助B这个跳板登录到C。此处一个简单示例为:从172.16.10.5登录到172.16.10.6,再以此为基础登录到172.16.100.3上。
[root@xuexi ~]# ssh 172.16.10.6The authenticity of host '172.16.10.6 (172.16.10.6)' can't be established.RSA key fingerprint is f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '172.16.10.6' (RSA) to the list of known hosts. Last login: Wed Jul 5 12:36:51 2017 from 172.16.10.6
[root@xuexi ~]# ssh 172.16.10.3The authenticity of host '172.16.10.3 (172.16.10.3)' can't be established.ECDSA key fingerprint is 18:d1:28:1b:99:3b:db:20:c7:68:0a:f8:9e:43:e8:b4. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '172.16.10.3' (ECDSA) to the list of known hosts. root@172.16.10.3's password:Last login: Thu Jun 29 12:38:56 2017 from 172.16.10.6
[root@xuexi ~]# hostname -I172.16.10.3 172.16.10.4
同样,在退出时,也是一层一层退出的。
[root@xuexi ~]# exit logout Connection to 172.16.10.3 closed. [root@xuexi ~]# hostname -I 172.16.10.6[root@xuexi ~]# exit logout Connection to 172.16.10.6 closed.
注意,由于在借助172.16.10.6当跳板连接到172.16.10.3,所以172.16.10.3的host key是添加到172.16.10.3上而非172.16.10.5上的。
如果在命令行给出了要执行的命令,默认ssh将工作在前台,如果同时给定了"-f"选项,则ssh工作在后台。但尽管是工作在后台,当远程执行的命令如果有消息返回时,将随时可能显示在本地。当远程命令执行完毕后,ssh连接也将立即关闭。
[root@xuexi ~]# ssh 172.16.10.6 'sleep 5' # 在前台睡眠5秒钟 [root@xuexi ~]# ssh 172.16.10.6 -f 'sleep 5;echo over' # 在后台睡眠5秒,睡眠完成后echo一段信息
由于第二条命令是放在后台执行的,所以该ssh一建立完成ssh会话就立即返回本地bash环境,但当5秒之后,将在本地突然显示"over"。
ssh执行远程命令默认允许从标准输入中读取数据然后传输到远程。可以使用"-n"选项,使得标准输入重定向为/dev/null。例如:
[root@xuexi ~]# echo haha | ssh 172.16.10.6 'cat'haha [root@xuexi ~]# ssh 172.16.10.6 'cat' c63e8327f4334772e0cd0645af928a6f> ~/.ssh/authorized_keys"
该命令首先建立ssh连接,并在远程执行"umask 077"临时修改远程的umask值,使得远程创建的目录权限为700,然后判断远程主机上是否有~/.ssh目录,如果没有则创建,最后从标准输入中读取本地公钥文件~/.ssh/id_rsa.pub的内容并将其追加到~/.ssh/authorized_keys文件中。
如果将此命令改为如下命令,使用ssh的"-n"选项,并将追加重定向改为覆盖重定向符号。
[root@xuexi ~]# cat ~/.ssh/id_rsa.pub | ssh -n 172.16.10.6 "umask 077; test -d ~/.ssh || mkdir ~/.ssh ; cat > ~/.ssh/authorized_keys"
该命令的结果是清空远程主机172.16.10.6上的~/.ssh/authorized_keys文件,因为ssh的"-n"选项强行改变了ssh读取的标准输入为/dev/null。
scp是基于ssh的远程拷贝命令,也支持本地拷贝,甚至支持远程到远程的拷贝。
scp由于基于ssh,所以其端口也是使用ssh的端口。其实,scp拷贝的实质是使用ssh连接到远程,并使用该连接来传输数据。下文有scp执行过程的分析。
另外,scp还非常不占资源,不会提高多少系统负荷,在这一点上,rsync远不及它。虽然 rsync比scp会快一点,但rsync是增量拷贝,要判断每个文件是否修改过,在小文件众多的情况下,判断次数非常多,导致rsync效率较差,而scp基本不影响系统正常使用。
scp每次都是全量拷贝,在某些情况下,肯定是不及rsync的。
scp [-12BCpqrv] [-l limit] [-o ssh_option] [-P port] [[user@]host1:]src_file ... [[user@]host2:]dest_file 选项说明:-1:使用ssh v1版本,这是默认使用协议版本-2:使用ssh v2版本-C:拷贝时先压缩,节省带宽-l limit:限制拷贝速度,Kbit/s,1Byte=8bit,所以"-l 800"表示的速率是100K/S-o ssh_option:指定ssh连接时的特殊选项,一般用不上。-P port:指定目标主机上ssh端口,大写的字母P,默认是22端口-p:拷贝时保持源文件的mtime,atime,owner,group,privileges-r:递归拷贝,用于拷贝目录。注意,scp拷贝遇到链接文件时,会拷贝链接的源文件内容填充到目标文件中(scp的本质就是填充而非拷贝)-v:输出详细信息,可以用来调试或查看scp的详细过程,分析scp的机制
src_file是源位置,dest_file是目标位置,即将src_file复制到dest_file,其中src_file可以指定多个。由于源位置和目标位置都可以使用本地路径和远程路径,所以scp能实现本地拷贝到远程、本地拷贝到本地、远程拷贝到本地、远程拷贝到另一个远程。其中远程路径的指定格式为"user@hostname:/path",可以省略user,也可以省略":/path",省略":/path"时表示拷贝到目的用户的家目录下。
注意:scp拷贝是强制覆盖型拷贝,当有重名文件时,不会进行任何询问。
例如:
(1).本地拷贝到本地:/etc/fstab-->/tmp/a.txt。
[root@xuexi ~]# scp /etc/fstab /tmp/a.txt
(2).本地到远程:/etc/fstab-->172.16.10.6:/tmp/a.txt。
[root@xuexi ~]# scp /etc/fstab 172.16.10.6:/tmp fstab 100% 805 0.8KB/s 00:00
(3).远程到本地:172.16.10.6:/etc/fstab-->/tmp/a.txt。
[root@xuexi ~]# scp 172.16.10.6:/etc/fstab /tmp/a.txt fstab 100% 501 0.5KB/s 00:00
(4).远程路径1到远程路径2:172.16.10.6:/etc/fstab-->/172.16.10.3:/tmp/a.txt。
[root@xuexi ~]# scp 172.16.10.6:/etc/fstab 172.16.10.3:/tmp/a.txt fstab 100% 501 0.5KB/s 00:00 Connection to 172.16.10.6 closed.
scp的拷贝实质是建立ssh连接,然后通过此连接来传输数据。如果是远程1拷贝到远程2,则是将scp命令转换后发送到远程1上执行,在远程1上建立和远程2的ssh连接,并通过此连接来传输数据。
在远程复制到远程的过程中,例如在本地(172.16.10.5)执行scp命令将A主机(172.16.10.6)上的/tmp/copy.txt复制到B主机(172.16.10.3)上的/tmp目录下,如果使用-v选项查看调试信息的话,会发现它的步骤类似是这样的。
# 以下是从结果中提取的过程 # 首先输出本地要执行的命令 Executing: /usr/bin/ssh -v -x -oClearAllForwardings yes -t -l root 172.16.10.6 scp -v /tmp/copy.txt root@172.16.10.3:/tmp # 从本地连接到A主机 debug1: Connecting to 172.16.10.6 [172.16.10.6] port 22. debug1: Connection established. # 要求验证本地和A主机之间的连接 debug1: Next authentication method: password root@172.16.10.6's password: # 将scp命令行修改后发送到A主机上 debug1: Sending command: scp -v /tmp/copy.txt root@172.16.10.3:/tmp # 在A主机上执行scp命令 Executing: program /usr/bin/ssh host 172.16.10.3, user root, command scp -v -t /tmp # 验证A主机和B主机之间的连接 debug1: Next authentication method: password root@172.16.10.3's password: # 从A主机上拷贝源文件到最终的B主机上 debug1: Sending command: scp -v -t /tmp Sending file modes: C0770 24 copy.txt Sink: C0770 24 copy.txt copy.txt 100% 24 0.0KB/s # 关闭本地主机和A主机的连接 Connection to 172.16.10.6 closed.
也就是说,远程主机A到远程主机B的复制,实际上是将scp命令行从本地传输到主机A上,由A自己去执行scp命令。也就是说,本地主机不会和主机B有任何交互行为,本地主机就像是一个代理执行者一样,只是帮助传送scp命令行以及帮助显示信息。
其实从本地主机和主机A上的~/.ssh/know_hosts文件中可以看出,本地主机只是添加了主机A的host key,并没有添加主机B的host key,而在主机A上则添加了主机B的host key。
在身份验证阶段,由于默认情况下基于公钥认证的机制顺序优先于基于密码认证的机制,所以基于公钥认证身份,就可以免输入密码,即实现双机互信(实际上只是单方向的信任)。
基于公钥认证机制的认证过程在前文已经详细说明过了,如还不清楚,请跳回上文。
以下是实现基于公钥认证的实现步骤:
(1).在客户端使用ssh-keygen生成密钥对,存放路径按照配置文件的指示,默认是在~/.ssh/目录下。
[root@xuexi ~]# ssh-keygen -t rsa # -t参数指定算法,可以是rsa或dsa Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): # 询问私钥保存路径 Enter passphrase (empty for no passphrase): # 询问是否加密私钥文件 Enter same passphrase again: Your identification has been saved in /root/.ssh/id_rsa. Your public key has been saved in /root/.ssh/id_rsa.pub.
如果不想被询问,则可以使用下面一条命令完成:"-f"指定私钥文件,"-P"指定passphrase,或者"-N"也一样。
[root@xuexi ~]# ssh-keygen -t rsa -f ~/.ssh/id_rsa -P '' # 指定加密私钥文件的密码为空密码,即不加密 [root@xuexi ~]# ssh-keygen -t rsa -f ~/.ssh/id_rsa -N '' # 同上
查看~/.ssh/目录下私钥的权限。私钥文件有严格的权限要求,当私钥文件的非所有者有可读权限时,将直接忽略该私钥文件导致公钥认证失败。
[root@xuexi ~]# ls -l ~/.sshtotal 12-rw------- 1 root root 1671 Jun 29 00:18 id_rsa # 私钥权限必须600,属主为自己-rw-r--r-- 1 root root 406 Jun 29 00:18 id_rsa.pub-rw-r--r-- 1 root root 393 Jun 29 05:56 known_hosts
(2).将上面生成的公钥使用ssh-copy-id分发(即复制)到远程待信任主机上。
ssh-copy-id用法很简单,只需指定待信任主机及目标用户即可。如果生成的公钥文件,路径不是~/.ssh/id_rsa.pub,则使用"-i"选项指定要分发的公钥。
ssh-copy-id [-i [identity_file]] [user@]machine
例如,将公钥分发到172.16.10.6上的root用户家目录下:
[root@xuexi ~]# ssh-copy-id 172.16.10.6
ssh-copy-id唯一需要注意的是,如果ssh服务端的端口不是22,则需要给ssh-copy-id传递端口号,传递方式为"-p port_num [user@]hostname",例如"-p 22222 root@172.16.10.6"。之所以要如此传递,见下面摘自ssh-copy-id中公钥分发的命令部分。
{ eval "$GET_ID" ; } | ssh $1 "umask 077; test -d ~/.ssh || mkdir ~/.ssh ; cat >> ~/.ssh/authorized_keys && (test -x /sbin/restorecon && /sbin/restorecon ~/.ssh ~/.ssh/authorized_keys >/dev/null 2>&1 || true)" || exit 1
其中"{ eval "$GET_ID" ; }"可理解为待分发的本地公钥内容,"(test -x /sbin/restorecon && /sbin/restorecon ~/.ssh ~/.ssh/authorized_keys >/dev/null 2>&1 || true)"和selinux有关,不用管,所以上述命令简化为:
cat ~/.ssh/id_rsa.pub | ssh $1 "umask 077; test -d ~/.ssh || mkdir ~/.ssh ; cat >> ~/.ssh/authorized_keys || exit 1
可见,ssh-copy-id的所有参数都是存储在位置变量$1中传递给ssh,所以应该将ssh的端口选项"-p port_num"和user@hostname放在一起传递。
通过分析上面的命令,也即知道了ssh-copy-id的作用:在目标主机的指定用户的家目录下,检测是否有~/.ssh目录,如果没有,则以700权限创建该目录,然后将本地的公钥追加到目标主机指定用户家目录下的~/.ssh/authorized_keys文件中。
就这样简单的两步就实现了基于公钥的身份认证。当然,不使用ssh-copy-id,也一样能实现上述过程。更便捷地,可以写一个简单的脚本,简化上述两个步骤为1个步骤。
#!/bin/bash ########################################################### # description: public key authentication in one step # # author : 骏马金龙 # # blog : http://www.cnblogs.com/f-ck-need-u/ ############################################################ privkey="$HOME/.ssh/id_rsa"publickey="$HOME/.ssh/id_rsa.pub" # Usage helpif [ $# -ne 1 ];then echo "Usage:$0 [user@]hostname" exit 1fi # test private/publick key exist or not, and the privilege 600 or notif [ -f "$privkey" -a -f "$publickey" ];then privkey_priv=`stat -c %a $privkey` if [ "$privkey_priv" -ne 600 ];then echo "The privilege of private key ~/.ssh/id_rsa is not 600, exit now." exit 1 fielse echo "private/public key is not exist, it will create it" ssh-keygen -t rsa -f $privkey -N '' echo "keys created over, it located on $HOME/.ssh/"fi ssh-copy-id "-o StrictHostKeyChecking=no $1" if [ $? -eq 0 ];then echo -e "\e[31m publickey copy over \e[0m"else echo "ssh can't to the remote host" exit 1fi
该脚本将检查本地密钥对~/.ssh/{id_rsa,id_rsa.pub}文件是否存在,还检查私钥文件的权限是否为600。如果缺少某个文件,将自动新创建密钥对文件,最后分发公钥到目标主机。
对于基于公钥认证的身份验证机制,除了上面客户端分发公钥到服务端的方法,还可以通过分发服务端私钥到客户端来实现。
先理清下公钥认证的原理:客户端要连接服务端,并告诉服务端要使用那对密钥对,然后客户端访问自己的私钥,服务端检测对应的公钥来决定该公钥所对应的客户端是否允许连接。所以对于基于公钥认证的身份验证,无论是客户端分发公钥,还是服务端分发私钥,最终客户端保存的一定是私钥,服务端保存的一定是公钥。
那么服务端分发私钥实现公钥认证是如何实现的呢?步骤如下:假如客户端为172.16.10.5,服务端为172.16.10.6。
(1).在服务端使用ssh-keygen生成密钥对。
[root@xuexi ~]# ssh-keygen -f ~/.ssh/id_rsa -P ''
(2).将上面生成的公钥追加到自己的authorized_keys文件中。
[root@xuexi ~]# ssh-copy-id 172.16.10.6
(3).将私钥拷贝到客户端,且路径和文件名为~/.ssh/id_rsa。
[root@xuexi ~]# scp -p ~/.ssh/id_rsa* 172.16.10.5:/root/.ssh/
注意,第三步中也拷贝了公钥,原因是客户端连接服务端时会比较自己的公钥和私钥是否配对,如果不配对将直接忽略公钥认证机制,所以会要求输入密码。可以将客户端的公钥删除掉,或者将服务端生成的公钥覆盖到客户端的公钥上,都能完成公钥认证。
虽说,服务端分发私钥的方式很少用,但通过上面的步骤,想必对ssh基于公钥认证的身份验证过程有了更深入的理解。
expect工具可以在程序发出交互式询问时按条件传递所需的字符串,例如询问yes/no自动传递y或yes,询问密码时自动传递指定的密码等,这样就能让脚本完全实现非交互。
显然,ssh等客户端命令基于密码认证时总是会询问密码,即使是基于公钥认证,在建立公钥认证时也要询问一次密码。另外,在ssh主机验证时还会询问是否保存host key。这一切都可以通过expect自动回答。
关于expect工具,它使用的是tcl语言,虽说应用在expect上的tcl语言并非太复杂,但这并非本文内容,如有兴趣,可网上搜索或直接阅读man文档。
首先安装expect工具。
[root@xuexi ~]# yum -y install expect
以下是scp自动问答的脚本。
[root@xuexi ~]# !/usr/bin/ { send
用法:autoscp.exp [user@]hostname src_file dest_file [password]
该自动回答脚本可以自动完成主机验证和密码认证,即使已经是实现公钥认证的机器也没问题,因为公钥认证机制默认优先于密码认证,且此脚本的password项是可选的,当然,在没有实现公钥认证的情况下,password是必须项,否则expect实现非交互的目的就失去意义了。
以下是几个示例:
[root@xuexi ~]# ./autoscp.exp 172.16.10.6 /etc/fstab /tmp 123456spawn scp /etc/fstab 172.16.10.6:/tmp The authenticity of host '172.16.10.6 (172.16.10.6)' can't be established.RSA key fingerprint is f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf. Are you sure you want to continue connecting (yes/no)? yes # 主机验证时询问是否保存host key,自动回答yes Warning: Permanently added '172.16.10.6' (RSA) to the list of known hosts. root@172.16.10.6's password: # 密码认证过程,自动回答指定的密码"123456"fstab 100% 805 0.8KB/s 00:00
也可以指定完成的用户名和主机名。
[root@xuexi ~]# ./autoscp.exp root@172.16.10.6 /etc/fstab /tmp 123456spawn scp /etc/fstab root@172.16.10.6:/tmp root@172.16.10.6's password: fstab 100% 805 0.8KB/s 00:00
以下是在建立公钥认证机制时,ssh-copy-id拷贝公钥到服务端的自动应答脚本。
[root@xuexi ~]# cat /tmp/autocopy.exp #!/usr/bin/expect ########################################################### # description: scp without interactive # # author : 骏马金龙 # # blog : http://www.cnblogs.com/f-ck-need-u/ ############################################################ set timeout 10set user_hostname [lindex $argv 0] set password [lindex $argv 1] spawn ssh-copy-id $user_hostname expect {"(yes/no)?"{ send "yes\n"expect "*assword:" { send "$password\n"} }"*assword:"{ send "$password\n"} } expect eof
用法:autocopy.exp [user@]hostname password
以下是一个示例,
[root@xuexi ~]# /tmp/autocopy.exp root@172.16.10.6 123456spawn ssh-copy-id root@172.16.10.6The authenticity of host '172.16.10.6 (172.16.10.6)' can't be established.RSA key fingerprint is f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf. Are you sure you want to continue connecting (yes/no)? yes # 主机认证时,自动应答yes Warning: Permanently added '172.16.10.6' (RSA) to the list of known hosts. root@172.16.10.6's password: # 密码认证时自动输入密码"123456"Now try logging into the machine, with "ssh 'root@172.16.10.6'", and check in: .ssh/authorized_keys to make sure we haven't added extra keys that you weren't expecting.
如果要实现批量非交互,则可以写一个shell脚本调用该expect脚本。例如:
[root@xuexi ~]# cat /tmp/sci.sh#!/bin/bash ########################################################### # description: scp without interactive # # author : 骏马金龙 # # blog : http://www.cnblogs.com/f-ck-need-u/ ############################################################ passwd=123456 # 指定要传递的密码为123456 user_host=`awk '{print $3}' ~/.ssh/id_rsa.pub` # 此变量用于判断远程主机中是否已添加本机信息成功 for i in $@ do/tmp/autocopy.exp $i $passwd >&/dev/nullssh $i "grep "$user_host" ~/.ssh/authorized_keys" >&/dev/null # 判断是否添加本机信息成功if [ $? -eq 0 ];thenecho "$i is ok"elseecho "$i is not ok"fidone
用法:/tmp/sci.sh [user@]hostname
其中hostname部分可以使用花括号展开方式枚举。但有个bug,最好ssh-copy-id的目标不要是脚本所在的本机,可能会强制输入本机密码,但批量脚本autocopy.exp则没有此bug。
例如:
[root@xuexi tmp]# /tmp/sci.sh 172.16.10.3 172.16.10.6172.16.10.3 is ok172.16.10.6 is ok
[root@xuexi tmp]# /tmp/sci.sh 172.16.10.{3,6}172.16.10.3 is ok172.16.10.6 is ok
[root@xuexi tmp]# /tmp/sci.sh root@172.16.10.3 172.16.10.6root@172.16.10.3 is ok172.16.10.6 is ok
ssh连接包括两个阶段:主机验证阶段和身份验证阶段。这两个阶段都可能导致连接速度慢。
具体是哪个阶段的速度慢,完全可以通过肉眼看出来:
(1).卡着很久才提示保存host key肯定是主机验证过程慢。
(2).主机验证完成后卡着很久才提示输入密码,肯定是身份验证过程慢。
其中主机验证过程慢的原因,可能是网络连接慢、DNS解析慢等原因。网络连接慢,ssh对此毫无办法,而DNS解析慢,ssh是可以解决的,解决方法是将ssh服务端的配置文件中UseDNS设置为no(默认为yes)。
而身份验证慢的原因,则考虑ssh的身份验证顺序:gssapi,host-based,publickey,keyboard-interactive,password。其中gssapi认证顺序是比较慢的,所以解决方法一是在ssh客户端配置文件中将GSSAPI认证机制给关掉,解决方法二是在ssh客户端配置文件中使用PreferredAuthentications指令修改身份验证顺序。
方法一修改:GSSAPIAuthentication yes
方法二修改:PreferredAuthentications publickey,password,gssapi,host-based,keyboard-interactive
如果感受不到哪个阶段导致速度变慢,可以使用ssh或scp等客户端工具的"-vvv"选项进行调试,看看是卡在哪个地方,不过,想看懂"-vvv"的过程,还是比较考验耐心的。
如下图,假如host3和host1、host2都同互相通信,但是host1和host2之间不能通信,如何从host1连接上host2?
对于实现ssh连接来说,实现方式很简单,从host1 ssh到host3,再ssh到host2,也就是将host3作为跳板的方式。但是如果不是ssh,而是http的80端口呢?如何让host1能访问host2的80端口?
ssh支持本地端口转发,语法格式为:
ssh -L [bind_addr:]local_port:remote:remote_port middle_host
以上图为例,实现方式是在host1上执行:
[root@xuexi ~]# ssh -g -L 2222:host2:80 host3
其中"-L"选项表示本地端口转发,其工作方式为:在本地指定一个由ssh监听的转发端口(2222),将远程主机的端口(host2:80)映射为本地端口(2222),当有主机连接本地映射端口(2222)时,本地ssh就将此端口的数据包转发给中间主机(host3),然后host3再与远程主机的端口(host2:80)通信。
现在就可以通过访问host1的2222端口来达到访问host2:80的目的了。例如:
再来解释下"-g"选项,指定该选项表示允许外界主机连接本地转发端口(2222),如果不指定"-g",则host4将无法通过访问host1:2222达到访问host2:80的目的。甚至,host1自身也不能使用172.16.10.5:2222,而只能使用localhost:2222或127.0.0.1:2222这样的方式达到访问host2:80的目的,之所以如此,是因为本地转发端口默认绑定在回环地址上。可以使用bind_addr来改变转发端口的绑定地址,例如:
[root@xuexi ~]# ssh -L 172.16.10.5:2222:host2:80 host3
这样,host1自身就能通过访问172.16.10.5:2222的方式达到访问host2:80的目的。
一般来说,使用转发端口,都建议同时使用"-g"选项,否则将只有自身能访问转发端口。
再来分析下转发端口通信的过程。
当host4发起172.16.10.5:2222的连接时(即步骤①),数据包的目标地址和端口为"172.16.10.5:2222"。由于host1上ssh已经监听了2222端口,并且知道该端口映射自哪台主机哪个端口,所以将会把该数据包目标地址和端口替换为"172.16.10.3:80",并将此数据包通过转发给host3。当host3收到该数据包时,发现是host1转发过来请求访问host2:80的数据包,所以host3将代为访问host2的80端口。
所以,host1和host3之间的通信方式是SSH协议,这段连接是安全加密的,因此称为"安全隧道",而host3和host2之间通信协议则是HTTP而不是ssh。
现在再来考虑下,通过本地端口转发的方式如何实现ssh跳板的功能呢?仍以上图为例:
[root@xuexi ~]# ssh -g -L 22333:host2:22 host3
这样只需使用ssh连上host1的22333端口就等于连接了host2的22端口。
甚至还可以在host3上执行:
[root@xuexi ~]# ssh -L 172.16.10.5:22333:host2:80 host2 或: [root@xuexi ~]# ssh -L 172.16.10.5:22333:host2:80 host3
这样在host3就开启了一个转发端口22333供host1连接。当host1连接到host3:22333时,host3将转发给host2或host3自身,再由host2或host3自身与host2通信。
最后,关于端口转发有一个需要注意的问题:ssh命令中带有要执行的命令。考虑了下面的三条在host1上执行的命令的区别。
[root@xuexi ~]# ssh -g -L 22333:host2:22 host3 [root@xuexi ~]# ssh -g -L 22333:host2:22 host3 "ifconfig"[root@xuexi ~]# ssh -g -L 22333:host2:22 host3 "sleep 10"
第一条命令开启了本地端口转发,且是以登录到host3的方式开启的,所以执行完该命令后,将跳到host3主机上,当退出host3时,端口转发功能将被关闭。另外,host1上之所以要开启端口转发,目的是为了与host2进行通信,而不是跳到host3上,所以应该在ssh命令行上加上"-f"选项让ssh在本机host1上以后台方式提供端口转发功能,而不是跳到host3上来提供端口转发功能。
第二条命令在开启本地转发的时候还指定了要在host3上执行"ifconfig"命令,但是ssh的工作机制是远程命令执行完毕的那一刻,ssh关闭连接,所以此命令开启的本地端口转发功能有效期只有执行ifconfig命令的一瞬间。
第三条命令和第二条命令类似,只不过指定的是睡眠10秒命令,所以此命令开启的本地转发功能有效期只有10秒。
结合上面的分析,开启端口转发功能时,建议让ssh以后台方式提供端口转发功能,且明确指示不要执行任何ssh命令行上的远程命令。即最佳开启方式为:
[root@xuexi ~]# ssh -f -N -g -L 22333:host2:22 host3
ssh除了支持本地端口转发,还支持远程端口转发。顾名思义,远程端口转发表示的是将远程端口的数据转发到本地。
如下图:假如host3是内网主机,它能和host2互相通信,也能和host1通信,但反过来,host1不能和host3通信。这时要让host1访问host3或host2就没办法通过本地端口转发了,因为要在host1上开启本地端口转发,必须要和host3通信请求建立隧道。
可以通过在host3上发起远程端口转发来实现,因为host3能和host1通信,host3可以请求在host1和host3之间建立隧道。
语法如下:
ssh -R [bind_addr:]remote1_port:host:port remote1
以上图为例,实现方式是在host3上执行:
[root@xuexi ~]# ssh -R 22333:host2:80 host1
这表示host3请求host1上的sshd服务,在host1上建立一个套接字监听22333端口,它是host2端口的映射,当有主机连接host1:22333时,此连接中的数据全部都通过host1和host3之间的安全隧道转发给host3,再由host3向host2的80端口发起访问。由于host3请求开启的转发端口是在远程主机host1上的,所以称为"远程端口转发"。
再考虑下面这条命令所开启的远程转发端口,它是在host3上执行的。
[root@xuexi ~]# ssh -R 22333:host3:80 host1
该命令将自身的host3:80映射到host1:22333上,这也能让host1和host2、host3通信,因为隧道是建立在host1:2233371fb34173e4ee87dab1f85dc1c283a44host3:80上的。
但是,远程端口转发和本地端口转发最大的一个区别是,远程转发端口是由host1上的sshd服务控制的,默认配置情况下,sshd服务只允许本地开启的远程转发端口(22333)绑定在环回地址(127.0.0.1)上,即使显式指定了bind_addr也无法覆盖。例如:
[root@xuexi ~]# ssh -R *:22333:host2:80 host1 [root@xuexi ~]# netstat -tnlp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 8405/sshd tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1422/master tcp 0 0 127.0.0.1:22333 0.0.0.0:* LISTEN 8407/sshd tcp 0 0 :::22 :::* LISTEN 8405/sshd tcp 0 0 ::1:25 :::* LISTEN 1422/master tcp 0 0 ::1:22333 :::* LISTEN 8407/sshd
要允许本地的远程转发端口绑定在非环回地址上,需要在host1的sshd配置文件中启用"GatewayPorts"项,它的默认值为no。启动该选项后,不给定bind_addr或bind_addr设置为"*"都表示绑定在所有地址上。如下:
[root@xuexi ~]# ssh -g -R *:22333:host2:80 host1 [root@xuexi ~]# netstat -tnlp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 8466/sshd tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1422/master tcp 0 0 0.0.0.0:22333 0.0.0.0:* LISTEN 8468/sshd tcp 0 0 :::22 :::* LISTEN 8466/sshd tcp 0 0 ::1:25 :::* LISTEN 1422/master tcp 0 0 :::22333 :::* LISTEN 8468/sshd
和前面的本地转发端口一样,建议的几个选项是:"-g"、"-f"、"-N"。即推荐的命令写法是:
[root@xuexi ~]# ssh -fgN -R 22333:host2:80 host1
现在,就可以通过访问host1:22333达到访问host2:80的目的了。如下图所示。
无论是本地端口转发还是远程端口转发,都是将某固定主机及其端口映射到本地或远程转发端口上,例如将host2:80映射到host1:2222。也就是说,本地或远程转发端口和目标端口所代表的应用层协议是一对一的关系,2222端口必须对应的是http的80端口,使用浏览器向host1:2222端口发起http请求当然没问题,但是使用ssh工具向host1:2222发起连接将会被拒绝,因为host2上http服务只能解析http请求,不能解析ssh连接请求。
ssh支持动态端口转发,由ssh来判断发起请求的工具使用的是什么应用层协议,然后根据判断出的协议结果决定目标端口。
以下图为例进行说明,host1处在办公内网,能和host3互相通信,但它无法直接和互联网和host2通信,而host3则可以和host2以及互联网通信。
要让host1访问互联网,又能和host2的22端口即ssh服务通信,显然在host1上仅设置一个本地端口转发是不够的,虽然可以设置多个本地转发端口分别映射不同的端口,但这显然比较笨重和麻烦。使用动态端口转发即可。
语法格式为:
ssh -D [bind_addr:]port remote
以上图为例,在host1上执行:
[root@xuexi ~]# ssh -Nfg -D 2222 host3
Nach der Ausführung des obigen Befehls startet Host1 den SOCKS4- oder SOCKS5-Dienst lokal, um Port 2222 abzuhören. Solange das Client-Programmtool (was den Typ des verwendeten Protokolls der Anwendungsschicht angibt) seinen eigenen Proxy auf Host1:2222 setzt, werden alle vom Programm generierten Daten an Host1:2222 und dann von Host1 weitergeleitet :2222 leitet die Daten über den Tunnel an Host3 weiter, und schließlich kommuniziert Host3 mit dem Internet oder dem Port des Anwendungsschichtprotokolls des entsprechenden Client-Tools auf Host2.
Tatsächlich ist es sehr einfach, wenn host4 den IE-Browser als Client-Tool verwendet und den Proxy des IE-Browsers auf host1:2222 setzt, da die vom IE-Browser initiierte Anfrage das http-Protokoll verwendet (hier nicht verwendet). Unter Berücksichtigung anderer möglicher Protokolle werden die vom IE-Browser generierten Daten an Host1:2222 weitergeleitet, und Host1:2222 leitet sie dann über den Tunnel an Host3 weiter. Host3 kann eine Verbindung zum Internet herstellen, sodass Host4 die Netzwerkfunktion realisiert. Stellen Sie es wie unten gezeigt ein:
Ein weiteres Beispiel ist, dass der QQ-Client auf Host4 auch einen Proxy festlegen kann. Auf diese Weise werden die von QQ generierten Daten über Host1:2222 weitergeleitet, und Host1:2222 leitet die QQ-Daten an Host3 weiter. Host3 weiß, dass das von diesen Daten verwendete Protokoll oicq ist, sodass Host3 eine Verbindung zum QQ-Server von Tencent herstellt (. entsprechend dem OICQ-Service-Port).
ssh unterstützt nur Socks4- und Socks5-Proxys. Einige Client-Tools müssen den Proxy-Typ klar angeben.
Wie bei der lokalen und Remote-Portweiterleitung sind die empfohlenen Optionen: „-f“, „-N“ und „-g“.
Da die dynamische SSH-Portweiterleitung eine Funktion des SSH-Clients ist, kann der Proxy-Internetzugang mithilfe von SSH-Client-Tools wie SecurtCRT und Putty ohne Verwendung des SSH-Befehls erreicht werden. Wenn der lokale Host beispielsweise nicht auf das Internet zugreifen kann, aber mit dem SSH-Dienst von 172.16.10.6 kommunizieren kann und 172.16.10.6 auf das Internet zugreifen kann, können Sie zunächst SecurtCRT verwenden, um eine Verbindung zu 172.16.10.6 auf dem lokalen Host herzustellen Nehmen Sie dann die folgenden Einstellungen an den entsprechenden Sitzungsoptionen vor, damit der lokale Host auch auf das Internet zugreifen kann. (Hinweis: Ich habe nicht gesagt, dass Sie FQ können, gute Bürger nicht FQ!!!)
Überprüfen Sie dann, ob SecurtCRT aktiv ist Überwacht auf dem lokalen Host Der in 8888 angegebene dynamische Weiterleitungsport.
Jetzt fließen alle Datenpakete dieser Maschine über 172.16.10.6, die mit SecurtCRT verbunden ist, nach außen.
Das obige ist der detaillierte Inhalt vonGrundlegende Einführung in SSH und SSH-Dienste (einschließlich Tunnelinhalt). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!