SSH远程登录工笔记

一、SSH 概述

1.1 SSH 概述

SSH(安全外壳协议)是一种在不安全的网络中通过加密来实现安全连接的网络协议,用于以加密方式远程登录其它计算机系统,通过SSH,用户可以安全地在远程服务器上进行文件传输和命令执行等操作。除了基本的远程终端功能外,SSH还提供了诸如远程命令执行、端口转发、数据隧道等高级功能。

Tips: sshd 是应用层和传输层的 SSH 服务

1.2 SSH相关各种文件分布

以主机A连接主机B为例,主机A为SSH客户端,主机B为SSH服务端。

在服务端即主机B上

  • /etc/ssh/sshd_config :ssh服务程序sshd的配置文件。
  • /etc/ssh/ssh_host_* :服务程序sshd启动时生成的服务端公钥和私钥文件。如ssh_host_rsa_key和ssh_host_rsa_key.pub。
    • 其中.pub文件是主机验证时的host key,将写入到客户端的~/.ssh/known_hosts文件中。
    • 其中私钥文件严格要求权限为600,若不是则sshd服务可能会拒绝启动。
  • ~/.ssh/authorized_keys:保存的是基于公钥认证机制时来自于客户端的公钥。在基于公钥认证机制认证时,服务端将读取该文件。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
cat /etc/ssh/sshd_config
Port 22                 # 服务端SSH端口,可以指定多条表示监听在多个端口上 
ListenAddress 0.0.0.0   # 监听的IP地址。0.0.0.0表示监听所有IP 
Protocol 2              # 使用SSH 2版本 ##################################### 
# 私钥保存位置 # ##################################### 
# HostKey for protocol version 1 
HostKey /etc/ssh/ssh_host_key       # SSH 1保存位置/etc/ssh/ssh_host_key 
# HostKeys for protocol version 2 #
HostKey /etc/ssh/ssh_host_rsa_key   # SSH 2保存RSA位置/etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_dsa_key   # SSH 2保存DSA位置/etc/ssh/ssh_host_dsa _key 

################################### 
# 杂项配置 # ################################### 
PidFile /var/run/sshd.pid # 服务程序sshd的PID的文件路径 
ServerKeyBits 1024 # 服务器生成的密钥长度 
SyslogFacility AUTH # 使用哪个syslog设施记录ssh日志。日志路径默认为/var/log/secure 
LogLevel INFO # 记录SSH的日志级别为INFO ################################### 

# 以下项影响认证速度 # ################################### 
UseDNS yes # 指定是否将客户端主机名解析为IP,以检查此主机名是否与其IP地址真实对应。默认yes。 # 由此可知该项影响的是主机验证阶段。建议在未配置DNS解析时,将其设置为no,否则主机验证阶段会很慢 

################################### 
# 以下是和安全有关的配置 
###################################
PermitRootLogin yes # 是否允许root用户登录
GSSAPIAuthentication no # 是否开启GSSAPI身份认证机制,默认为yes
PubkeyAuthentication yes # 是否开启基于公钥认证机制
AuthorizedKeysFile .ssh/authorized_keys # 基于公钥认证机制时,来自客户端的公钥的存放位置 
PasswordAuthentication yes # 是否使用密码验证,如果使用密钥对验证可以关了它
PermitEmptyPasswords no # 是否允许空密码,如果上面的那项是yes,这里最好设置no 
MaxSessions 10 # 最大客户端连接数量
LoginGraceTime 2m # 身份验证阶段的超时时间,若在此超时期间内未完成身份验证将自动断开
MaxAuthTries 6 # 指定每个连接最大允许的认证次数。默认值是6。 # 如果失败认证次数超过该值一半,将被强制断开,且生成额外日志消息。 
MaxStartups 10 # 最大允许保持多少个未认证的连接。默认值10。 
################################### 
# 以下可以自行添加到配置文件
################################### 
DenyGroups hellogroup testgroup # 表示hellogroup和testgroup组中的成员不允许使用sshd服务,即拒绝这些用户连接 
DenyUsers hello test # 表示用户hello和test不能使用sshd服务,即拒绝这些用户连接 
################################### 
# 以下一项和远程端口转发有关 
################################### 
GatewayPorts no # 设置为yes表示sshd允许被远程主机所设置的本地转发端口绑定在非环回地址上 # 默认值为no,表示远程主机设置的本地转发端口只能绑定在环回地址上,见后文"远程端口转发"

在客户端即主机A上

  • /etc/ssh/ssh_config :客户端的全局配置文件。
  • ~/.ssh/config :客户端的用户配置文件,生效优先级高于全局配置文件。一般该文件默认不存在。该文件对权限有严格要求只对所有者有读/写权限,对其它人完全拒绝写权限。
  • ~/.ssh/known_hosts :保存主机验证时服务端主机host key的文件。文件内容来源于服务端的ssh_host_rsa_key.pub文件。
  • /etc/ssh/known_hosts:全局host key保存文件。作用等同于~/.ssh/known_hosts。
  • ~/.ssh/id_rsa :客户端生成的私钥。由ssh-keygen生成。该文件严格要求权限,当其他用户对此文件有可读权限时,ssh将直接忽略该文件。
  • ~/.ssh/id_rsa.pub :私钥id_rsa的配对公钥。对权限不敏感。当采用公钥认证机制时,该文件内容需要复制到服务端的 ~/.ssh/authorized_keys 文件中。
  • ~/.ssh/rc :保存的是命令列表,这些命令在ssh连接到远程主机成功时将第一时间执行,执行完这些命令之后才开始登陆或执行ssh命令行中的命令。
  • /etc/ssh/rc :作用等同于~/.ssh/rc。

1.3 基于公钥认证机制实现双机互信

实现基于公钥认证的实现步骤:

  • 在客户端使用ssh-keygen生成密钥对,存放路径按照配置文件的指示,默认是在 ~/.ssh/ 目录下。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
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"也一样。
ssh-keygen -t rsa -f ~/.ssh/id_rsa -P '' # 指定加密私钥文件的密码为空密码,即不加密 
ssh-keygen -t rsa -f ~/.ssh/id_rsa -N '' # 同上


# 查看 ~/.ssh/ 目录下私钥的权限。私钥文件有严格的权限要求,当私钥文件的非所有者有可读权限时,将直接忽略该私钥文件导致公钥认证失败。
ls -l ~/.ssh 
total 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
  • 将生成的公钥 id_rsa.pub 使用 ssh-copy-id 分发(即复制)到远程待信任主机上。

ssh-copy-id用法很简单,只需指定待信任主机及目标用户即可。如果生成的公钥文件路径不是 ~/.ssh/id_rsa.pub,则使用 -i 选项指定要分发的公钥。

1
ssh-copy-id [-i [identity_file]] [user@]host

Tips: ssh-copy-id的作用是在目标主机的指定用户的家目录下,检测是否有~/.ssh目录,如果没有,则以700权限创建该目录,然后将本地的公钥追加到目标主机指定用户家目录下的~/.ssh/authorized_keys文件中。

ssh-copy-id 唯一需要注意的是,如果ssh服务端的端口不是22,则需要给 ssh-copy-id 指定传递端口号,传递方式为 “-p port_num [user@]hostname” (注意加上双引号),例如:ssh-copy-id “-p 22222 root@172.16.10.6”。

二、SSH 常用命令

2.1 SSH基本用法 - 远程登录

1
ssh -p 22 user@host

参数:

  • -p:指定端口号。
  • user:登录的用户名,(连同@)省略时用户名与本地主机用户名相同。
  • host:登录的主机。

SSH服务端(sshd)默认的端口号为22,当端口号为22的时候,可以省略,直接使用如下方式:

1
ssh user@host

2.2 SSH的远程操作

在远程的机器上面执行操作,格式如下:

1
ssh user@host 'command'

command: 为 要执行的 shell 命令

案例1:在机器A(192.168.13.148)中查看机器B(192.168.13.149)的操作系统类型。

在A机器上面执行如下代码:

1
ssh dequan@192.168.1.2 'uname -a'

案例2:将机器A(192.168.13.148)中test文件夹复制到B机器(192.168.13.149)。

在A机器上面,执行如下命令:

1
tar -cz test | ssh dequan@192.168.1.2 'tar -xz'

三、SSH 端口转发

3.1 SSH端口转发的概念

SSH端口转发是一种通过SSH协议在本地和远程主机之间建立安全通道,实现端口之间的数据转发,也称为SSH隧道。它允许在不直接访问目标主机的情况下,通过安全的SSH连接来访问该主机上的服务。通过SSH端口转发,可以将本地端口与远程主机上的服务端口相关联(映射),使得在本地主机上运行的应用程序能够通过SSH隧道与远程主机上的服务进行通信。

SSH端口转发通常被用来绕过防火墙等设备穿透到内网,或用于保护TCP连接等。

SSH端口转发有三种常见的类型:本地端口转发(Local Port Forwarding)远程端口转发(Remote Port Forwarding)动态端口转发(Dynamic Port Forwarding)

SSH端口转发是一种强大而灵活的功能,通过安全的SSH连接,可以将流量从一个端口转发到另一个端口。

SSH端口转发常用参数:

  • -C:压缩数据
  • -f:后台认证用户/密码,通常和-N连用,不用登录到远程主机。
  • -N:不执行脚本或命令,通常与-f连用。
  • -g:在-L/-R/-D参数中,允许远程主机连接到建立的转发的端口,如果不加这个参数,只允许本地主机建立连接。
  • -L: 本地端口:目标IP:目标端口
  • -D: 动态端口转发
  • -R: 远程端口转发
  • -T:不分配 TTY 只做代理用
  • -q:安静模式,不输出 错误/警告 信息

3.2 本地端口转发

本地端口转发(local port forwarding) 是最常用的SSH端口转发类型之一。它允许将本地主机上的一个端口(local_port)转发到远程主机上的另一个端口(remote_port)。当需要通过SSH访问位于防火墙后面或者只能在远程主机上访问的服务时,本地端口转发非常有用。通过本地端口转发,可以在本地主机上创建一个监听指定端口(local_port)的SSH隧道,将该端口(local_port)上的流量转发到远程主机上的指定端口(remote_port)。这样,就可以通过本地主机上的端口(local_port)与远程主机上的服务进行通信。即 访问本地主机端口(local_port),实际上是访问远程主机(remote_host)的端口(remote_port)

Tips: 我们把执行本地转发命令的设备称为本地主机。

命令格式:

1
2
# 这条命令表示将本地主机的某个端口(本地端口)映射到远程主机的某个端口(远程端口),通过 SSH 服务器进行连接。
ssh -f -N -L [local_ip:]local_port:remote_host:remote_port [user@]ssh_server
  • -f -N 参数设置 命令后台运行
  • local_ip 可以省略(省略时默认值为:localhost/127.0.0.1),也可指定为本机网口的 IP 或 0.0.0.0(全部网口)
  • ssh_server 可以是 本机 或 任意 本机可通过 ssh 访问的 远程主机
  • remote_host 可以是 ssh_server 或 任意 ssh_server 主机可 访问的 远程主机

alt text

流量转发流程:

  • SSH 客户端会监听本地的端口 local_port,把所有发给该端口的 TCP 报文都 通过 ssh 发给指定的 ssh_server 服务
  • ssh_server服务 收到这类报文 后再转发到目标主机服务(remote_host:remote_port)
  • 在目标机器看来,这个请求来自 ssh_server。

原型图: alt text

示例:

1
2
3
4
ssh -f -N -L 10443:192.168.1.20:443  root@192.168.1.10                  # 只能在本机访问 127.0.0.1:10443 ,将被转发到 192.168.1.20:443
ssh -f -N -L 127.0.0.1:10443:192.168.1.20:443  root@192.168.1.10        # 只能在本机访问 127.0.0.1:10443 ,将被转发到 192.168.1.20:443
ssh -f -N -L 192.168.1.10:10443:192.168.1.20:443  root@192.168.1.10     # 可以在本机 或与 192.168.1.10 互通的任意主机上 访问 192.168.1.10:10443 服务,将被转发到 192.168.1.20:443
ssh -f -N -L 0.0.0.0:10443:192.168.1.20:443  root@192.168.1.10          # 可以在本机 或与 192.168.1.10 互通的任意主机上 访问 192.168.1.10:10443 服务,将被转发到 192.168.1.20:443

3.3 远程端口转发

远程端口转发(remote port forwarding) 是另一种常见的SSH端口转发类型。它允许将远程主机上的一个端口(remote_port)的流量通过SSH隧道传输(转发)到本地主机上的另一个端口(local_port)。将远程主机(remote)上的端口流量 通过 ssh 转发到本地(ssh 客户端)机器上的端口,本机(ssh 服务器)再转发到目标机器上的端口。

当需要将远程主机上的某个服务映射到本地主机上,或者需要远程主机上的其它计算机访问本地主机上的服务时,远程端口转发非常有用。通过远程端口转发,可以在远程主机上创建一个监听指定端口(remote_port)的SSH隧道,将该端口(remote_port)上的流量转发到本地主机上的指定端口(local_port)。这样,远程主机上的流量就可以通过SSH隧道传输到本地主机上的指定端口(port1),实现服务的访问。

alt text

  • 用户 A 发起连接:用户A在本地主机上使用SSH命令发起远程转发连接。示例命令为:
  • 建立 SSH 连接:本地主机与 SSH 服务器之间建立 SSH 连接。这一步骤确保所有数据都通过安全的 SSH 隧道传输。
  • 用户 B 访问服务:远程主机上的用户 B 试图通过 SSH 服务器访问本地主机上的服务。
  • 请求转发:SSH 服务器接收到用户 B 的请求后,通过已建立的 SSH 隧道将请求转发到用户 A 的本地主机上的端口。
  • 响应返回:本地主机将响应通过 SSH 隧道发送回 SSH 服务器,SSH 服务器再将响应转发回远程主机。

命令格式:

1
2
3
4
5
# [remote:]remote_port - 远程 SSH 服务器上的 IP 和端口号。空的 remote 意味着远程 SSH 服务器将绑定到所有接口。
# destination:destination_port - 目标机器的 IP 或主机名和端口。
# [user@]server_ip - 远程 SSH 用户和服务器 IP 地址。
ssh -r [remote:]remote_port:destination:destination_port [user@]ssh_server
#   该命令中,远程端口是SSH服务器上的端口,本地主机是用户A的本地计算机,本地端口是本地主机上的端口,用户名是SSH服务器上的用户名,SSH服务器是远程SSH服务器的地址。

远程转发应用场景

假设在本地计算机上运行了一个 Web 服务器(例如:localhost:80),希望通过中转服务器 sshserver.com 让远程用户访问该 Web 服务器。

1
ssh -R 8080:localhost:80 user@sshserver.com

执行上述命令后,远程用户可以通过访问 sshserver.com:8080 来连接到本地计算机上的 Web 服务器。 alt text

  • 在本地计算机上运行 ssh -R 8080:localhost:80 user@sshserver.com
  • SSH 服务器在 sshserver.com:8080 上监听。
  • 当远程用户连接到 sshserver.com:8080 时,SSH 服务器通过 SSH 隧道将请求转发到本地计算机上的 localhost:80。
  • 本地计算机返回的响应通过相同的路径返回到远程用户。

3.4 动态端口转发

SSH 动态转发(SSH Dynamic Port Forwarding)是一种通过 SSH 隧道实现的代理功能,它允许在本地计算机上创建一个 SOCKS 代理服务器,从而使得所有通过这个代理的流量都通过 SSH 隧道加密并转发到远程服务器。与本地转发和远程转发不同,动态转发不需要预先指定目标主机和端口,而是可以动态地决定目的地,这使其更加灵活。

动态端口转发 是SSH端口转发的另一种类型,也称为SSH动态代理。与本地端口转发和远程端口转发只能将一个端口进行转发不同,动态端口转发可以创建一个动态代理通道,将本地主机上的多个端口转发到远程主机上。通过动态端口转发,可以在本地主机上创建一个监听指定端口的SSH隧道,将本地主机上的流量通过SSH通道转发到远程主机上,然后再由远程主机发送到最终的目标地址。动态端口转发通常用于代理服务器或通过中间节点访问特定网络资源。

alt text

  • 用户发起连接:用户在本地主机上使用 SSH 命令发起动态转发连接。示例命令为:
  • 建立 SSH 连接:本地主机与 SSH 服务器之间建立 SSH 连接。这一步确保所有数据都通过安全的 SSH 隧道传输。
  • 设置本地 SOCKS 代理:本地计算机在指定端口(例如 8080)上启动一个 SOCKS 代理。任何发送到该端口的流量都会通过 SSH 隧道转发到远程服务器。
  • 用户配置应用程序:用户配置需要通过代理访问网络的应用程序(如浏览器),使其使用本地 SOCKS 代理端口(例如 8080)。
  • 应用程序发出请求:用户在应用程序中访问某个远程服务器(例如访问某个网站)。应用程序的请求首先发送到本地 SOCKS 代理端口。
  • 请求转发:本地计算机捕获通过 SOCKS 代理端口的请求,通过已建立的 SSH 隧道将请求加密并转发到 SSH 服务器。
  • SSH 服务器处理请求:SSH 服务器接收到请求后,根据请求中的目标地址和端口访问远程服务器。
  • 远程服务器处理请求并返回响应:远程服务器接收请求后进行处理,生成响应数据,并将其返回给 SSH 服务器。SSH 服务器将响应数据通过 SSH 隧道加密并发送回本地主机。

那么我们都有了远程转发和本地转发,为什么还需要动态转发呢?

那么我们思考这样一个问题,如果我们本地转发的目的端口为443,对端是一个HTTPS服务,在我们通过浏览器访问时,由于本地监听的地址为localhost,则会出现证书无法被验证的问题。还有假设这个Web服务器将我们重定向至另一个URL,很有可能将连接失败,例如在使用单点登录时(SSO),这种情况很可能出现问题。

使用动态转发则能够解决这个问题,动态转发的实现是SSH通过在本地建立Socks代理,然后通过SSH转发到远程主机,然后远程主机再将SSH内的数据包转发至内网主机。

命令格式:

1
2
# 该命令中,本地代理端口是本地计算机上打开的SOCKS代理端口,用户名是SSH服务器上的用户名,SSH服务器是远程SSH服务器的地址。
ssh -D 本地代理端口 用户名@SSH服务器

3.5 SSH端口转发的用途

SSH端口转发具有广泛的用途,以下是其中一些常见的应用场景:

  1. 安全远程访问

通过SSH端口转发,您可以安全地访问位于防火墙后面的远程主机或仅在内部网络中可访问的服务。通过建立SSH隧道,您可以将本地主机上的某个端口转发到远程主机上,然后通过SSH连接进行访问。这样,您就可以使用SSH协议的加密和身份验证功能来保护远程访问的安全性。

  1. 跨越网络限制

在某些情况下,您可能面临着网络限制,无法直接访问某些服务或资源。使用SSH端口转发,您可以绕过这些限制,通过建立安全的SSH通道将流量转发到允许访问的网络上。这对于跨越防火墙或访问受限制的网络资源非常有用。

  1. 加密流量传输

SSH端口转发不仅仅用于访问远程服务,还可以用于加密流量传输。通过将本地主机上的流量通过SSH隧道转发到远程主机上,然后再由远程主机发送到最终的目标地址,您可以确保数据在传输过程中受到SSH协议的加密保护。这对于传输敏感数据或在不受信任的网络上操作非常重要。

  1. 跨越 NAT 网络

NAT(Network Address Translation)是一种常见的网络配置,用于在私有网络和公共网络之间转换IP地址。当您需要在私有网络中访问公共网络上的服务时,NAT可能会导致问题。通过使用SSH端口转发,您可以将本地主机上的流量通过SSH隧道转发到公共网络上的服务。这样,您可以绕过NAT限制,实现私有网络与公共网络之间的通信。

  1. 安全代理

动态端口转发可以用作安全代理,通过建立动态代理通道将本地主机上的流量转发到远程主机上。这对于通过中间节点访问受限制的网络资源非常有用。通过SSH端口转发,您可以在本地主机上配置代理设置,使得所有的网络流量都通过SSH隧道转发到远程主机上,然后再由远程主机发送到最终的目标地址。