1.1 Connaissances de base du cryptage asymétrique
Cryptage symétrique : le cryptage et le décryptage utilisent le même algorithme, à condition que le décryptage et le cryptage sont fournis. Le décryptage peut être complété avec un mot de passe cohérent. Par exemple, mot de passe de connexion QQ, mot de passe de carte bancaire, assurez-vous simplement que le mot de passe est correct.
Cryptage asymétrique : Crypter et déchiffrer à l'aide d'une clé publique et d'une clé privée. Le contenu chiffré avec la clé publique peut être déchiffré à l'aide de la clé privée, et le contenu chiffré avec la clé privée peut être déchiffré à l'aide de la clé publique. Généralement, le chiffrement par clé publique et le déchiffrement par clé privée sont utilisés, mais ce n'est pas absolument le cas. Par exemple, lorsqu'une autorité de certification signe un certificat, elle utilise sa propre clé privée pour le chiffrement. Dans le service SSH présenté ensuite, bien qu'il soit toujours recommandé de distribuer des clés publiques, des clés privées peuvent également être distribuées.
Donc, si A génère (clé privée A, clé publique A) et que B génère (clé privée B, clé publique B), alors la situation de session de chiffrement asymétrique entre A et B comprend :
(1).A distribue sa clé publique A à B, B crypte les données avec la clé publique A, et envoie les données cryptées à A. A utilisera sa clé privée A pour décrypter les données.
(2).A distribue sa clé publique A à B et utilise sa propre clé privée A pour crypter les données, puis B utilise la clé publique A pour déchiffrer les données.
(3).B distribue sa clé publique B à A. A prend la clé publique B pour chiffrer les données et envoie les données chiffrées à B. B utilisera sa clé privée B pour les déchiffrer.
(4).B distribue sa clé publique B à A et utilise sa propre clé privée B pour crypter les données, puis A utilise la clé publique B pour déchiffrer les données.
Bien que supporte théoriquement 4 scénarios, lors de la phase d'authentification de SSH, SSH ne prend en charge que le serveur conservant la clé publique et le client conservant la clé privée , Donc là Il n'y a que deux manières : le client génère une paire de clés et distribue la clé publique au serveur ; le serveur génère une paire de clés et distribue la clé privée au client. Cependant, pour des raisons de sécurité et de commodité, le client génère généralement la paire de clés et distribue la clé publique. Des exemples de ces deux méthodes de distribution sont donnés ci-dessous.
(1). SSH est un protocole de sécurité sur la couche transport et la couche application. Il ne peut assurer la sécurité de la connexion qu'en cryptant les sessions entre les deux parties. Lorsque la connexion ssh réussit, une session entre le client et le serveur sera établie. La session est cryptée et toutes les communications ultérieures entre le client et le serveur seront transmises via la session.
(2). Le processus démon du service SSH est sshd, qui écoute sur le port 22 par défaut.
(3). Tous les outils clients ssh, y compris les commandes ssh, scp, sftp, ssh-copy-id et d'autres commandes, utilisent des connexions ssh pour effectuer des tâches. C'est-à-dire qu'ils sont tous connectés au port 22 du serveur, mais après avoir été connectés, les commandes pertinentes à exécuter sont converties et transmises à l'hôte distant pour exécution par l'hôte distant.
(4) La commande client .ssh (ssh, scp, sftp, etc.) lit deux fichiers de configuration : le fichier de configuration global /etc/ssh/ssh_config et le fichier de configuration utilisateur ~/.ssh/config . En fait, les options de configuration peuvent également être transmises sur la ligne de commande. La priorité à laquelle ils prennent effet est : options de configuration de la ligne de commande > ~/.ssh/config >
(5).ssh implique deux vérifications : la vérification de l'hôte et l'authentification de l'utilisateur. Grâce à la vérification de l'hôte, puis à la vérification de l'utilisateur sur l'hôte, l'identité de l'utilisateur peut être déterminée de manière unique. Il peut y avoir plusieurs utilisateurs sur un hôte, donc chaque hôte ne doit être authentifié qu'une seule fois, mais chaque utilisateur sur l'hôte doit être authentifié individuellement.
(6).ssh prend en charge plusieurs mécanismes d'authentification, les plus couramment utilisés étant le mécanisme d'authentification par mot de passe et le mécanisme d'authentification par clé publique. Le mécanisme d'authentification par clé publique est presque nécessaire pour obtenir une confiance mutuelle entre deux machines dans certains scénarios. Bien que les deux mécanismes d'authentification ci-dessus soient couramment utilisés, l'ordre par défaut lors de l'authentification est gssapi-with-mic, basé sur l'hôte, clé publique, clavier interactif, mot de passe. Notez que le mécanisme d'authentification de l'hôte basé sur l'hôte n'est pas l'authentification de l'hôte puisque l'authentification de l'hôte est rarement utilisée (le fichier d'authentification qu'il lit est /etc/hosts.equiv ou /etc/shosts.equiv), il est rarement vu sur le réseau. . En général, modifier l'ordre d'authentification à l'aide de la commande PreferredAuthentications dans le fichier de configuration ssh (notez le fichier de configuration sshd) peut être considéré comme un moyen d'améliorer l'efficacité de la vérification.
(7). Le client ssh possède en fait de nombreuses fonctions puissantes, telles que la redirection de port (mode tunnel), l'authentification proxy, le partage de connexion (multiplexage de connexion), etc.
(8). Le fichier de configuration du serveur ssh est /etc/ssh/sshd_config. Notez qu'il se distingue du fichier de configuration global du client /etc/ssh/ssh_config.
(9). Le point le plus important est que SSH demandera l'attribution d'un pseudo terminal lors de la connexion. Cependant, certains programmes d'authentification tels que sudo peuvent interdire ce type d'allocation de terminal, provoquant l'échec de la connexion ssh. Par exemple, lorsque vous utilisez ssh pour exécuter la commande sudo, sudo vérifiera si vous souhaitez attribuer un terminal à ssh.
Si vous vous connectez du client A (172.16.10.5) au serveur B (172.16.10.6), il inclura Le deux processus d'authentification de l'hôte et d'authentification de l'identité de l'utilisateur prennent comme exemple l'algorithme de chiffrement asymétrique RSA.
[root@xuexi ~]# ssh 172.16.10.6
Le programme de service sshd est d'abord démarré sur le serveur B, c'est-à-dire que le service ssh est activé et le port 22 est ouvert (par défaut).
Lorsque le client A souhaite se connecter à B, il effectuera d'abord un processus de vérification de l'hôte, c'est-à-dire déterminera si l'hôte B s'est déjà connecté.
La façon de déterminer est de lire le fichier ~/.ssh/known_hosts et le fichier /etc/ssh/known_hosts, et de rechercher les informations sur l'hôte de 172.16.10.6 (l'hôte Ces informations sont appelées clé d'hôte, indiquant l'identité de l'hôte). Si la clé d'hôte correspondant à l'adresse n'est pas trouvée, demandez s'il faut enregistrer la clé d'hôte envoyée par l'hôte B. Si la clé d'hôte de l'adresse est trouvée, comparez la clé d'hôte avec la clé d'hôte envoyée par l'hôte B. Si s'ils sont exactement les mêmes, cela signifie que l'hôte A a déjà enregistré la clé d'hôte de l'hôte B. Il n'est pas nécessaire de la sauvegarder à nouveau et il passera directement au processus suivant - l'authentification. Si ce n'est pas exactement la même, ce sera le cas. demander s'il faut enregistrer la clé d'hôte actuellement utilisée par l'hôte B.
Le processus pour demander s'il faut enregistrer la clé d'hôte est le suivant :
[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
Ou utilisez le interface graphique côté Windows Lors de l'utilisation de l'outil client ssh :
Avant d'expliquer le processus d'authentification, jetons un œil au format du fichier known_hosts. Prenons ~/.ssh/known_hosts comme exemple.
[root@xuexi ~]# cat ~/.ssh/known_hosts172.16.10.6 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC675dv1w+GDYViXxqlTspUHsQjargFPSnR9nEqCyUgm5/32jXAA3XTJ4LUGcDHBuQ3p3spW/eO5hAP9eeTv5HQzTSlykwsu9He9w3ee+TV0JjBFulfBR0weLE4ut0PurPMbthE7jIn7FVDoLqc6o64WvN8LXssPDr8WcwvARmwE7pYudmhnBIMPV/q8iLMKfquREbhdtGLzJRL9DrnO9NNKB/EeEC56GY2t76p9ThOB6ES6e/87co2HjswLGTWmPpiqY8K/LA0LbVvqRrQ05+vNoNIdEfk4MXRn/IhwAh6j46oGelMxeTaXYC+r2kVELV0EvYV/wMa8QHbFPSM6nLz
Dans ce fichier, chaque ligne a une clé d'hôte, et le début de la ligne est le nom d'hôte, qui est utilisé lors de la recherche de Index de la clé d'hôte , le contenu après le nom d'hôte est la partie de la clé d'hôte. En prenant ce fichier comme exemple, cela indique que le client A a déjà essayé de se connecter à l'hôte B à l'adresse 172.16.10.6 et a enregistré la clé d'hôte de l'hôte B. La prochaine fois qu'il se connectera à l'hôte B, il recherchera la clé d'hôte de l'hôte B. B et faites-la correspondre avec 172.16. Comparez la clé d'hôte envoyée par 10.6. Si elle correspond, cela signifie que la clé d'hôte est bien la clé d'hôte actuellement utilisée par 172.16.10.6. Si elle ne peut pas correspondre, cela signifie que 172.16.10.6 a été modifié. la clé de l'hôte, ou la clé de l'hôte dans ce fichier La clé de l'hôte a été modifiée.
Alors, où est stockée la clé d'hôte actuellement utilisée par l'hôte B ? Dans le fichier /etc/ssh/ssh_host*, ces fichiers sont reconstruits au démarrage du programme de service sshd du serveur (ici, l'hôte B). En prenant l'algorithme rsa comme exemple, il est stocké dans /etc/ssh/ssh_host_rsa_key et /etc/ssh/ssh_host_rsa_key.pub. Le fichier de clé publique /etc/ssh/ssh_host_rsa_key.pub stocke la clé de l'hôte.
[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
J'ai constaté que le contenu du fichier /etc/ssh/ssh_host_rsa_key.pub est exactement le même que la partie clé de l'hôte dans ~ /.ssh/known_hosts, uniquement Cependant, en plus de la partie clé de l'hôte, il existe un nom d'hôte supplémentaire dans ~/.ssh/known_hosts, qui est l'index lors de la recherche de l'hôte.
Pour résumer, Pendant la phase de vérification de l'hôte, le serveur détient la clé privée, et le client détient la clé publique du serveur. Notez que c'est l'opposé de qui détient la clé pendant la phase d'authentification.
En fait, ssh ne compare pas directement la clé hôte car la clé hôte est trop longue et l'efficacité de la comparaison est faible. Ainsi, ssh convertit la clé hôte en empreinte digitale de clé hôte, puis compare les empreintes digitales de clé hôte des deux côtés. Le format de l'empreinte digitale est le suivant :
[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
L'empreinte digitale de la clé hôte peut être calculée par ssh-kegen. Par exemple, voici les empreintes digitales de la clé d'hôte enregistrées par l'hôte A (172.16.10.5) et les empreintes digitales de la clé d'hôte actuellement utilisée par l'hôte B (172.16.10.6). On voit qu'ils sont exactement les mêmes.
[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)
En fait, ssh prend également en charge la comparaison floue de clé hôte, qui convertit la clé hôte en une empreinte graphique. De cette manière, des résultats graphiques très différents peuvent être facilement comparés. La raison pour laquelle on parle de comparaison floue est que ssh peut mal évaluer des empreintes graphiques très similaires. L'empreinte graphique est générée comme suit : Ajoutez simplement une option "-v" à la commande ci-dessus pour passer en mode détaillé.
[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). L'ancienne ligne de commande ssh ne contient aucun paramètre de commande, ce qui signifie qu'un utilisateur sur l'hôte distant (ici l'utilisateur root) est utilisé pour se connecter à l'hôte distant 172.16.10.6, donc l'hôte distant L'hôte allouera un pseudo-terminal et entrera dans l'environnement bash.
(2). Cette dernière ligne de commande ssh a des paramètres de commande, ce qui signifie exécuter la commande donnée [echo "haha"] sur l'hôte distant. Les commandes à distance sur la ligne de commande ssh sont exécutées via le processus enfant obtenu par fork ssh-agent. Lorsque la commande est exécutée, le processus enfant disparaît, ssh se ferme également et les sessions et connexions établies sont également fermées. (La raison pour laquelle nous devons expliquer clairement le processus d'exécution des commandes à distance ici est d'expliquer les précautions lors de la mise en œuvre de la redirection de port avec ssh qui seront introduites plus tard)
En fait, une fois la connexion ssh réussie, connectez-vous dans ou exécuter la ligne de commande Avant de saisir la commande, vous pouvez spécifier la commande à exécuter à distance. Ces commandes sont placées dans le fichier ~/.ssh/rc ou /etc/ssh/rc. faire une fois la connexion ssh établie est d'exécuter la commande à distance. Exécutez les commandes dans ces deux fichiers sur l'hôte.
Prenons l'exemple de l'hôte A se connectant à l'hôte B. L'hôte A est un client SSH et l'hôte B est un serveur SSH. .
Sur le serveur, hôte B :
/etc/ssh/sshd_config : fichier de configuration sshd du programme de service ssh .
/etc/ssh/ssh_host_* : Les fichiers de clé publique et de clé privée du serveur générés au démarrage du programme de service sshd. Tels que ssh_host_rsa_key et ssh_host_rsa_key.pub.
Les exigences strictes du fichier de clé privée sont 600. Si ce n'est pas le cas, le service SSHD peut refuser de démarrer.
Sur le client, hôte A :
Ce fichier nécessite strictement des autorisations. Lorsque d'autres utilisateurs disposent d'autorisations de lecture pour ce fichier,
Le fichier sera simplement être ignoré.
~/.ssh/id_rsa.pub : La clé publique appariée à la clé privée id_rsa. Non sensible aux autorisations. Lors de l'utilisation du mécanisme d'authentification par clé publique, le contenu de ce fichier doit être copié dans le fichier
~/.ssh/RC : La liste des commandes est enregistrée. Ces commandes seront exécutées dès que la connexion SSH à l'hôte distant est réussie
Il est divisé en fichier de configuration du serveur /etc/ssh/sshd_config et fichier de configuration du client /etc/ssh/ssh_config (global) ou ~/.ssh/config (utilisateur).
虽然服务端和客户端配置文件默认已配置项虽然非常少非常简单,但它们可配置项非常多。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之间不同通信,即A<-->B<-->C<-x->A的情形。如果要从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' </etc/fstab
再看如下两条命令:
[root@xuexi ~]# tar zc /tmp/* | ssh 172.16.10.6 'cd /tmp;tar xz' [root@xuexi ~]# ssh 172.16.10.6 'tar cz /tmp' | tar xz
第一条命令将/tmp下文件归档压缩,然后传送到远程主机上并被解包;第二条命令将远程主机上的/tmp目录归档压缩,并传输到本地解包。所以它们实现了拷贝的功能。
不妨再分析下面的命令,该命令改编自ssh-copy-id脚本中的主要命令。如果不知道ssh-copy-id命令是干什么的,后文有介绍。
[root@xuexi ~]# cat ~/.ssh/id_rsa.pub | ssh 172.16.10.6 "umask 077; test -d ~/.ssh || mkdir ~/.ssh ; cat >> ~/.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:22333<-->host3: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
Après avoir exécuté la commande ci-dessus, host1 démarrera le service SOCKS4 ou SOCKS5 localement pour écouter sur le port 2222. Tant que l' outil du programme client (impliquant le type de protocole de couche application utilisé) définit son propre proxy sur host1:2222, toutes les données générées par le programme seront transmises à host1:2222, puis par Host1 :2222 transmet les données à l'hôte3 via le tunnel, et enfin l'hôte3 communique avec Internet ou le port du protocole de couche application de l'outil client correspondant sur l'hôte2.
En fait, c'est très simple. Si host4 utilise le navigateur IE comme outil client et définit le proxy du navigateur IE sur host1:2222, puisque la requête initiée par le navigateur IE utilise le protocole http (non utilisé ici) En considérant d'autres protocoles possibles), les données générées par le navigateur IE sont transmises à host1:2222, puis host1:2222 les transmettent à host3 via le tunnel Host3 peut se connecter à Internet, afin que host4 réalise la fonction réseau. Définissez comme indiqué ci-dessous :
Un autre exemple est que le client QQ sur host4 peut également définir un proxy. De cette façon, les données générées par QQ seront transmises via host1:2222, et host1:2222 transmettra les données QQ à host3. Host3 sait que le protocole utilisé par ces données est oicq, donc host3 se connectera au serveur QQ de Tencent (. correspondant au port de service oicq).
ssh ne prend en charge que les proxys chaussettes4 et chaussettes5. Certains outils clients doivent indiquer clairement le type de proxy.
Identique à la redirection de port local et distant, les options recommandées sont : "-f", "-N" et "-g".
Étant donné que la redirection de port dynamique ssh est une fonction du client ssh, l'accès Internet proxy peut être obtenu en utilisant des outils client ssh tels que SecurtCRT et putty sans utiliser la commande ssh. Par exemple, si l'hôte local ne peut pas accéder à Internet, mais peut communiquer avec le service SSH de 172.16.10.6 et que 172.16.10.6 peut accéder à Internet, vous pouvez d'abord utiliser SecurtCRT pour vous connecter à 172.16.10.6 sur l'hôte local, et puis effectuez les réglages suivants sur les options de session correspondantes, afin que l'hôte local puisse également accéder à Internet. (Remarque : je n'ai pas dit que vous pouvez FQ, les bons citoyens ne font pas FQ !!!)
Ensuite, vérifiez si SecurtCRT est en cours surveillé sur l'hôte local Le port de transfert dynamique 8888 spécifié dans .
Désormais, tous les paquets de données de cette machine circulent vers le monde extérieur via 172.16.10.6 connecté à SecurtCRT.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!