Contents

SSH隧道和代理

1. 简介

我们可以使用的更通用的工具之一是ssh 。作为管理远程主机的首选远程访问工具而广为人知,它具有许多非常有用的附加便利功能。例如,我们可以使用ssh传输文件 ,将远程主机挂载为网络文件系统 ,并生成密钥

在本教程中,我们将深入探讨ssh代理隧道 功能

2. 概念

从 TCP/IP 堆栈的早期开始,远程节点访问是必须的。然而,为它设计的协议——用于交互式访问的*telnet *和用于文件 传输的 FTP——缺乏一个非常基本的安全措施:数据流没有加密。

因此,使用这些协议传输的数据可以被*tcpdump * 和Wireshark 等网络流量分析工具捕获和审查。由于用户名和密码以明文形式交换,攻击者很容易收集它们。

为了解决这个问题和其他限制,** ssh在其连接中实现了加密**。这样,只要它使用了适当的配置、强加密和密钥交换模式,我们就可以确保我们的通信不会在途中被截获

更有用的功能之一,但并不广为人知,是建立隧道和代理的能力。这样,我们可以使用ssh会话连接其他对我们不可见的远程服务,例如受防火墙保护的服务:

/uploads/ssh_tunneling_and_proxying/1.svg

如图所示,客户端机器在打开ssh会话的同时,指示SSH 服务器打开可以双向工作的隧道

它还可以作为XWindows 协议的代理,允许我们在本地打开远程 GUI 应用程序,或者作为SOCKS 4 或 5 兼容的代理服务器,允许客户端从远程站点模拟 SSH 服务器访问多个目的地。

更令人印象深刻和危险的是,它支持完整的类似 VPN 的体验,它能够使用tun 设备对 2 级或 3 级数据包进行隧道传输。

3. 服务器配置

首先,我们可能会注意到,允许隧道通过ssh连接可能是一种安全隐患,因为它可以穿透我们的防火墙策略。因此,必须注意不要暴露我们可能希望对不需要的访问保持关闭的服务和主机。出于这个原因,一些 Linux 发行版默认禁用隧道和代理。

3.1. SSHD 选项

通过编辑*sshd_config 文件来启用*sshd * (服务于 ssh 会话的守护进程)。它的位置略有不同,但通常位于/etc/ssh/etc/openssh*上。相关的配置键是:

  • AllowStreamLocalForwarding:允许转发 Unix 域套接字。省略时,默认值为yes
  • AllowTcpForwarding:允许 TCP 端口转发。省略时,默认值是允许。它启用单个 TCP 端口转发和 socks 代理
  • DisableForwarding:禁用各种转发。覆盖(如果启用)所有其他相关配置选项
  • GatewayPorts:允许其他主机使用转发到客户端的端口(反向隧道)。默认情况下,只有运行 SSH 服务器的主机才能使用反向隧道。默认禁用
  • PermitListen:指定可以绑定以允许端口转发到客户端的地址和端口。如果我们启用GatewayPorts ,它会提供更精细的控制。默认为 localhost(‘127.0.0.1’ 和 ‘::1’)
  • PermitOpen:指定 TCP 转发可能指向的地址和端口。默认情况下,启用任何目的地
  • PermitTunnel:指定是否允许tun设备转发。默认为否
  • X11Forwarding:指定是否允许 X11 转发。默认为否
  • X11UseLocalhost:强制 X11 转发只允许来自 SSH 服务器主机环回地址。如果禁用,SSH 服务器网络上的其他主机可能会使用它。默认为真

3.2. 其他配置

主机上的其他配置可能会影响ssh的转发和代理能力。AppArmor  和SELinux 可能会禁止其中一些选项。此外,某些主机防火墙配置可能会限制连接到外部服务的能力(请参阅我们的iptables 教程 )。请注意,默认情况下,绑定 1024 下的监听端口需要 root 权限。

当然,中间防火墙必须允许 SSH 流量,通常在端口 TCP/22 上,但我们可以通过更改sshd_config文件中的默认值来使用其他端口。

4. 转发 TCP 隧道

4.1. 单端口

转发或直接 TCP 隧道是遵循从客户端到 SSH 服务器的 SSH 连接方向的隧道我们关于 SSH 的介绍性教程 简要描述了这种类型的转发。要创建直接 TCP 转发隧道,我们必须在命令行上使用*-L*选项:

ssh -L [bind_address:]port:host:hostport [user@]remote_ssh_server

可选的bind_address分配一个客户端本地接口来监听连接。如果我们省略它,ssh只会绑定在环回接口上。我们还可以使用*“0.0.0.0”“::”*来绑定所有接口。因此,如果我们发出以下命令:

ssh -L 0.0.0.0:8022:10.1.4.100:22 user@10.1.4.20

我们将在 10.1.4.20 IP 地址和一个隧道上打开到主机的 SSH 连接,监听客户端端口 8022,指向主机 10.1.4.100 上的 SSH 地址。

这样,如果连接进入客户端端口 8022,它将使用 SSH 服务器 IP 地址转发到目标主机和端口,看起来就像它们之间的常规本地网络。

同样,要转发本地套接字(不太常见),我们可以使用:

ssh -L local_socket:host:hostport [user@]remote_ssh_server

或者我们可以使用:

ssh -L local_socket:remote_socket [user@]remote_ssh_server

4.2. 动态或多端口

前向 TCP 隧道的一个特例是 Socks 代理功能。使用这些选项,SSH 客户端侦听指定的绑定端口并充当 SOCKS 4 或 5 代理服务器

任何使用 SOCKS 协议到绑定端口的连接都将使用其自己的 IP 地址转发到 SSH 服务器。为此,我们将使用:

ssh -D [bind_address:]port [user@]remote_ssh_server

请注意,在这种情况下,我们甚至不需要为转发指定目标主机和端口。指定端口上的所有符合 SOCKS 的传入连接都将流经隧道。

要使用它,我们当然必须配置将使用隧道的应用程序在命令行指定的绑定地址和端口上使用代理服务器。例如,发出后:

ssh -D 8080 user@10.1.4.100

我们可以在客户端主机上配置一个浏览器,以使用 127.0.0.1 端口 8080 上的 SOCKS 代理服务器。这样,我们可以像使用安装在 10.1.4.100 的 SSH 服务器上的浏览器一样浏览 Web。

如果客户端应用程序不支持 SOCKS 代理怎么办?我们可以使用代理链 或 tsocks 等解决方案来拦截套接字 系统调用并强制连接流经 SOCKS 代理。

5. 反向隧道

5.1. 单端口

反向或回调代理允许我们执行与上述类似的技巧,但方向相反。我们可以在自己的本地网络上向 SSH 会话远程端的主机打开服务。命令语法与直接转发非常相似:

ssh -R [bind_address:]port:host:hostport [user@]remote_ssh_server

这将创建一个反向隧道。它将远程 SSH 服务器上收到的任何连接转发到bind_address:port 到本地客户端网络host:hostport。 如果我们省略bind_address参数,它只绑定到环回接口。

同样,使用套接字,我们可以使用三种不同的语法:

ssh -R remote_socket:host:hostport [user@]remote_ssh_server
ssh -R remote_socket:local_socket [user@]remote_ssh_server
ssh -R [bind_address:]port:local_socket [user@]remote_ssh_server

5.2. 动态或多端口

最后,我们可以在远程主机上公开一个指向客户端网络的 SOCKS 代理服务器,就像我们可以使用直接转发一样。我们只能通过省略本地目标主机和端口来做到这一点:

ssh -R [bind_address:]port [user@]remote_ssh_server

这会在远程 SSH 服务器上打开一个端口,该端口将用作本地客户端网络的 SOCKS 服务器,可能会穿透任何适用于远程 SSH 服务器的出站流量规则。

6. X Windows 隧道

反向隧道的一种特殊情况是隧道 X11 连接的能力。这样,在 SSH 连接的远程端运行的 GUI 应用程序可以利用运行 X 服务器的本地端来公开它们的用户界面

SSH 负责建立所需的隧道。此外,它设置 SSH 服务器上 X 客户端应用程序所需的 DISPLAY 环境变量。这样,他们就会知道如何正确连接本地客户端的 X 服务器。

有两种 X11 转发,应用 X11 安全扩展限制(参见*xhost * 和*xauth *,以供参考):

ssh -X [user@]remote_ssh_server

或者假设一个不会强制执行 X11 安全扩展的可信环境创建隧道:

ssh -Y [user@]remote_ssh_server

7. 多隧道和多主机跳跃

我们可以根据需要创建任意数量的隧道,混合类型和方向。 我们可以通过在命令行中添加更多选项来实现这一点:

ssh -X -L 5432:<DB server IP>:5432 -R 873:<local RSYNC server>:873 [user@]remote_ssh_server

这会打开到远程 PostgreSQL 服务器的直接转发,到本地rsync服务器的反向隧道,并允许 GUI 应用程序流向我们的本地 X 服务器。

我们还可以使用 SSH 隧道到达更远的 SSH 服务器,为它们创建隧道,穿透我们需要的尽可能多的防火墙层,在每个连接上创建隧道,直到我们可以到达所需的点:

ssh -L 8022:<server2>:22 user@server1
ssh -L 8023:<server3>:22 -p 8022 user@localhost
ssh -p 8023 user@localhost

该序列在每个步骤中创建一条从server1server2到下一个服务器的隧道,直到在本地端口 8023 上打开的隧道允许我们到达server3

8. 配置文件

在复杂的场景中,在命令行上创建多个隧道可能会很棘手,因为它可能会导致很长的命令行。

这就是为什么** ssh最可爱的特性之一是允许在配置文件中使用任何命令行参数**。我们可以使用全局ssh客户端配置文件(位于/etc/ssh/ssh_config 或 /etc/openssh/ssh_config)或使用位于 ~/.ssh/config 的用户特定配置文件。如果它不存在,这是默认设置,我们将不得不创建一个新的。

在这些文件中,我们可以为每个常用端点指定默认配置,包括转发隧道和代理:

host 10.1.4.100
        ForwardX11 yes
        LocalForward 0.0.0.0:5432 10.1.4.200:5432
        RemoteForward localhost:8022 localhost:22
        user blogdemo

这将使用用户 ’ blogdemo ‘连接到 10.1.4.100 上的远程 SSH 服务器,允许:

  • X Windows 反向隧道
  • 从本地端口 5432 直接隧道到远程主机 10.1.4.200 端口 5432
  • SSH 服务器环回接口中端口 8022 上的反向/回调隧道到我们的本地客户端主机

还有许多其他选项可用,例如压缩、Kerberos 身份验证转发等。此外,主机规范允许使用通配符。

9. 持久隧道

顺便说一句,只要 SSH 连接保持,SSH 隧道就存在。即使我们甚至可以配置会话保持活动的频率和超时以促进连接丢失检测,但完全自动化 SSH 会话的创建和重新连接也会很好。

为此,一个方便的软件是autossh 。此实用程序可以自动创建和重新创建 SSH 会话。如果我们添加身份验证密钥,如我们的 SSH密钥 教程中所示,只要autossh正在运行,隧道就会在没有用户干预的情况下打开。它的语法是:

autossh [-V] [-M port[:echo_port]] [-f] [SSH_OPTIONS]
  • -V:显示autossh版本
  • -M:在端口上创建直接隧道,环回到反向隧道echo_port。它提供了一个活着的检查机制。但是,使用最近的 OpenSSH,我们可以使用sshd_config文件中的ServerAliveInterval 和ServerAliveCountMax选项来获得类似的结果
  • -f:在运行ssh之前强制**autossh在后台运行
  • SSH_OPTIONS : 我们用来启动ssh的选项

这样,要启动持久连接,我们可以使用:

autossh -X -L 5432:<DB server IP>:5432 -R 873:<local RSYNC server>:873 [user@]remote_ssh_server

如果我们定义了主机配置,命令行就简单多了:

autossh -f [host]