SSH 隧道技术
SSH (Secure Shell) 不仅是安全远程管理的工具,也是在主机之间创建安全隧道的强大工具。本文围绕 SSH 的隧道技术,探索隧道技术的原理与用途,并通过在多台主机上建立和使用正向隧道和反向隧道,实际体会隧道技术的作用。
正向 SSH 隧道
原理简介
正向 SSH 隧道 (本地端口转发) 是一种通过加密的 SSH 连接来转发本地机器上的端口到远程机器上的端口的技术。通过在本地机器上设置 SSH 隧道,用户可以安全地访问远程服务器上的资源。这种隧道的设置允许本地应用程序安全地连接到远程服务器上的服务,就像这些服务是在本地运行一样。
当设置了一个正向 SSH 隧道,就是在本地机器上创建了一个可以安全访问远程资源的“入口”。访问这个本地端口的所有请求都会通过加密的 SSH 连接被转发到远程服务器的指定端口上。这种机制常用于安全地访问部署在远程服务器上的数据库、Web 服务等。
使用
建立基本的正向 SSH 隧道的命令格式如下:
1 | ssh -L [local_address:]local_port:[remote_address]:remote_port username@ssh_server |
-L
:指定正向隧道,格式为 [local_address:]local_port:[remote_address]:remote_port
,其中
local_address
:可选参数,表示本地地址。- 通常可以缺省,默认只有本地可以连接远程端口,即
localhost
。 - 也可以绑定一个地址例如
0.0.0.0
,以便其他主机使用本机作为正向代理服务器。
- 通常可以缺省,默认只有本地可以连接远程端口,即
local_port
:表示本地机器上用于访问或发送数据的端口。remote_address
:表示远程网络中的目标地址,可以是 IP 或主机名。缺省参数,默认就是远程网络的
localhost
。在目标服务器和 SSH 服务器不是同一台服务器时,需要明确指定目标地址,不可缺省。
remote_port
:表示目标地址上用于连接服务的端口。
username@ssh_server
:远程 SSH 服务器的登录用户名和地址。
注意:正向隧道中的 local
是请求者,remote
是响应者,而远程 SSH 服务器不一定是目标服务器,但是要求一定能访问目标服务器。
常用辅助参数:
-f
:在后台执行 SSH 命令。-N
:不执行远程命令,常与端口转发一起使用。-v
,-vv
,-vvv
:增加命令的详细输出级别,用于调试。-C
:启用压缩,可以提高传输速度。-p 端口
:指定 SSH 服务器监听的端口 (如果不是默认的22端口)。-i 私钥文件
:使用指定的私钥文件进行身份验证。
场景案例
在正向 SSH 的场景中,目标服务器或服务通常位于客户端可以直接或间接访问的网络中。这意味着客户端可以通过 SSH 连接到一个中介服务器,然后通过 SSH 端口转发访问位于同一远程网络内的其他服务,即使这些服务没有直接对外开放。客户端使用 SSH 客户端软件建立连接,用于远程管理服务器或进行安全的文件传输。这样,正向 SSH 不仅适用于目标网络对外完全开放的情况,也适用于需要通过中介访问受限资源的场景。
案例
在服务器上启动一个 tomcat,在本地直接访问 服务器IP:8080
,大致有两种情况:
- 访问成功。在这种情况下使用正向 SSH 隧道更多是在开放或不受信任的网络中进行加密通信,防止中间人攻击等。
- 访问失败。在这种情况下使用正向 SSH 隧道更多是为了绕过网络限制和防火墙策略等。
在本地执行命令,在本地与 SSH 服务器之间创建正向的 SSH 隧道,分为两种情况:
SSH 服务器 (10.0.0.2) 和目标服务器 (10.0.0.2) 是同一台服务器
1
ssh -L 9090:localhost:8080 root@10.0.0.2
这个命令将本地的
9090
端口转发到远程 SSH 服务器上的localhost
的8080
端口。SSH 服务器 (10.0.0.2) 和目标服务器 (10.0.0.3) 不是同一台服务器,但是要确保 SSH 服务器能够访问目标服务器
1
ssh -L 9090:10.0.0.3:8080 root@10.0.0.2
这个命令将本地的
9090
端口转发到远程 SSH 服务器上的目标地址10.0.0.3
的8080
端口。
在本地访问 localhost:9090
,正常情况下应该能够看到 tomcat 的主页面。
反向 SSH 隧道
原理简介
反向 SSH 隧道 (远程端口转发) 是将远程服务器上的端口转发到本地机器上的端口的过程。这允许在远程服务器上运行的应用程序或用户通过这个端口安全地访问本地机器上运行的服务或应用。
当设置一个反向 SSH 隧道时,实际上是在远程服务器上创建了一个端口,当访问这个端口时,流量会通过 SSH 隧道转发到连接的本地机器的指定端口。这通常用于开发和测试阶段,允许远程团队成员或系统访问仅在开发者的本地机器上运行的应用。
使用
建立基本的反向 SSH 隧道的命令格式如下:
1 | ssh -R [remote_address:]remote_port:[local_address]:local_port username@ssh_server |
-R
:指定反向隧道,格式为 [remote_address:]remote_port:[local_address]:local_port
,其中
remote_address
:可选参数,表示远程地址。- 可以缺省,默认就是远程网络的
localhost
。 - 可以绑定一个地址例如
0.0.0.0
,以便其他主机使用本机进行通信,但是实际效果取决于GatewayPorts
的设置。
- 可以缺省,默认就是远程网络的
remote_port
:表示远程地址上用于连接服务的端口。local_address
:表示本地网络中的目标地址。如果确定本机就是服务提供者,可以缺省,默认就是本机地址。
在本地网络目标机器和本机不是同一台服务器时,需要明确指定目标地址,不可缺省。
local_port
:表示本地网络上用于提供服务的端口。
username@ssh_server
:远程 SSH 服务器的登录用户名和地址。
注意:在反向隧道中,remote
是请求者,local
是响应者,而远程 SSH 服务器则不再是一个关注重点,重点在于本地网络中提供具体服务的目标机器与执行反向 SSH 隧道命令的机器是否是同一台。
常用辅助参数:-f
, -N
, -v
, -C
, -p
, -i
:这些参数的功能与在ssh -L
中的功能相同。
服务端配置选项
GatewayPorts 是反向 SSH 隧道中一个比较重要的服务端配置选项。
GatewayPorts 在 /etc/ssh/sshd_config 配置文件中设置。如果设置在远程服务器的配置中,可以允许或拒绝转发的端口被远程主机上的其他客户端访问。
GatewayPorts 的三种设置:
- 默认情况下,即使指定了
remote_address
为0.0.0.0
(希望监听所有接口),如果远程服务器的GatewayPorts
设置为no
(默认设置),则实际上端口只会在localhost
上开放。这意味着无法从远程服务器之外的其他机器访问这个端口。 - 如果
GatewayPorts
设置为yes
,则remote_address
可以被设置为0.0.0.0
(或特定的外部地址),这样端口就会在指定的地址上开放,允许从任何可以访问该服务器的机器访问这个端口。 - 如果
GatewayPorts
设置为clientspecified
,则remote_address
可以指定一个特定的 IP 地址,表示仅允许从特定的 IP 地址访问这个端口。
推荐使用 GatewayPorts clientspecified
来手动控制客户端的访问权限。
场景案例
在反向 SSH 通常用于目标计算机位于受限网络环境中,无法被外部网络直接访问的情况。例如,服务器位于一个防火墙保护的内网中,或者服务器使用了 NAT 配置,使得外部网络不能直接访问服务器。
在这种情况下,位于内网中的服务器可以主动建立一个可访问的外部 SSH 服务器的连接。一旦连接建立,外部服务器可以通过这个反向隧道反向访问内网中的服务器。
反向 SSH 隧道适用于需要通过远程服务器代理访问本地或内网资源的场景,特别是当这些资源不能直接暴露给外部网络时。这种技术通过使用远程服务器作为一个跳板,使得本地服务可以安全地被外部访问,同时保持网络的封闭和安全。与正向 SSH 隧道相似,反向隧道为数据提供了加密的通道,确保传输的安全性。这使得反向 SSH 隧道成为远程访问和网络管理中一个非常有价值的工具。
案例
在本地网络中启动一个 tomcat,如果让一台位于外网的机器直接访问,通常只有访问失败的情况。这个时候,反向 SSH 隧道就是一种非常简单高效的内网穿透方案,只需要确保本机能够访问本地网络的服务。
在本机执行命令,在本机与远程 SSH 服务器之间创建反向的 SSH 隧道,分为两种情况:
本机 (192.168.1.2) 和在本地网络中提供具体服务的机器 (192.168.1.2) 是同一台
1
ssh -R 9090:localhost:8080 root@10.0.0.2
这个命令将远程 SSH 服务器的
9090
端口转发到本机上的localhost
的8080
端口。本机 (192.168.1.2) 和在本地网络中提供具体服务的机器 (192.168.1.3) 不是同一台,但是要确保本机能够访问目标机器
1
ssh -R 9090:192.168.1.3:8080 root@10.0.0.2
这个命令将远程 SSH 服务器的
9090
端口转发到本地网络的192.168.1.3
的8080
端口。
访问 SSH服务器IP:9090
,正常情况下应该能够看到 tomcat 的主页面。
补充
SSH 隧道可能会因为 SSH 长时间不执行命令或者网络问题而断开连接,可以使用一些 SSH 客户端配置选项来维持长时间的连接
1. ServerAliveInterval
ServerAliveInterval
用于配置 SSH 客户端向服务器发送消息的时间间隔,以保持连接活跃。如果设置了此选项,客户端将定期向服务器发送空包,以保持会话不被服务器因为超时而关闭。
使用方法:
在命令行中添加 -o ServerAliveInterval=n
,其中 n
是以秒为单位的时间间隔。例如,每 60 秒向服务器发送一次保持连接的消息:
1 | ssh -o ServerAliveInterval=60 username@server.com |
2. ServerAliveCountMax
ServerAliveCountMax
与 ServerAliveInterval
一起使用,用于定义在没有收到任何服务器响应的情况下,客户端尝试发送保持连接消息的最大次数。如果达到这个次数仍未收到响应,SSH 客户端将断开连接。
使用方法:
设置尝试次数,与 ServerAliveInterval
一起使用:
1 | ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 username@server.com |
这个配置表明,SSH 客户端每 60 秒向服务器发送一次消息,尝试最多 3 次,如果三次都没有响应,则客户端断开连接。
提示:在客户端配置选项较多的情况下,可以改写为配置文件的形式
1 | Host LTS |
使用 -F
参数指定配置文件,假设配置文件名为 ssh_lts_config
,对应的 HOST
为 LTS
则使用以下命令即可
1 | ssh -F ssh_lts_config LTS |
这样就简化了命令行的编写。
3. TCPKeepAlive
TCPKeepAlive
选项用于设置是否使用 TCP 层的 keepalive 特性来检测和保持网络连接活跃。默认情况下,这个选项通常是开启的。
使用方法:
如果需要显式开启或关闭,可以这样设置:
1 | ssh -o TCPKeepAlive=yes username@server.com |
或者关闭:
1 | ssh -o TCPKeepAlive=no username@server.com |
4. 实际应用
在一些长时间运行的 SSH 会话,如反向隧道或持续的远程监控中,合理设置这些参数可以显著提高连接的稳定性,减少由于网络间歇性问题导致的连接断开。
此外还可以考虑使用 autossh (自动重连)、mosh (针对网络不好的环境进行了优化)、Eternal Terminal (专注解决了断线重连的问题) 等更强大的工具,相关参考资料如下:
Mosh | archlinuxcn 、mosh | github
总结
SSH 隧道技术中,反向 SSH 隧道的实际应用可能更广泛一些,特别是需要从外网访问内网时,反向隧道让外部环境可以安全访问位于私有网络或内网中的服务和资源。对个人来说,反向隧道可以让外网很方便地访问本地服务,而往往这些服务不会部署到公网服务器上,例如一些简单的游戏联机服务,可能并没有提供一个统一的服务端,而是 P2P 联机的模式。这就可以通过反向 SSH 隧道来建立外网到内网的通信,使得在另一个内网的机器可以通过本地内网 —> 公网 —> 远程内网的链路,跨内网访问服务。
而正向 SSH 隧道更注重的是加密安全通信,特别是需要访问一些不希望暴露给整个互联网的服务,例如远程服务器上的数据库存储了很重要的数据,是不对公网开放的,这个时候就可以使用 SSH 加密连接到服务器,并将本地端口与远程服务器数据库的端口进行映射。Navicat 工具使用 SSH 隧道连接数据库就是基于这个正向 SSH 隧道技术实现的。
参考资料
- 标题: SSH 隧道技术
- 作者: Entropy Tree
- 创建于 : 2024-04-18 11:53:33
- 更新于 : 2024-07-26 17:17:05
- 链接: https://www.entropy-tree.top/2024/04/18/ssh-tunneling-techniques/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。