使用SSH反向代理和端口转发

一 为什么使用SSH代理?

我们访问局域网内的主机时,一般的做法是将要访问的服务的端口映射到防火墙(公网IP)上的某一个端口,然后通过访问公网IP:端口的形式访问服务,这也就直接将服务暴露在公网上了,进行一些端口扫描很容易发掘服务器开放了哪些端口。

下面的示例就是阿里云上的一台负载均衡服务器,为了从公司内部访问阿里云ECS主机上部署的服务,在负载均衡上开放了很多的端口。

docker@k8s01:~$ nmap -p1-65535 147.192.141.240
Starting Nmap 7.60 ( https://nmap.org ) at 2019-04-08 01:58 UTC
Nmap scan report for 147.192.141.240
Host is up (0.048s latency).
Not shown: 65522 filtered ports
PORT      STATE  SERVICE
80/tcp    open   http
443/tcp   open   https
1883/tcp  open   mqtt
2883/tcp  open   ndnp
4242/tcp  open   vrml-multi-use
4321/tcp  open   rwhois
5000/tcp  open   upnp
8443/tcp  closed https-alt
9443/tcp  open   tungsten-https
15672/tcp open   unknown
30258/tcp open   unknown
31928/tcp open   unknown
32195/tcp open   unknown
Nmap done: 1 IP address (1 host up) scanned in 120.11 seconds

可见一些常用服务很容易被识别出来,例如:

  • 5000端口(Docker Registry的服务端口)
  • 4242端口:opentsdb默认使用的端口
  • 15672:RabbitMQ的管理页面的端口
  • xxx22的端口一般是SSH服务端口等等

通过简单的猜测和尝试,就可能导致服务器的信息泄露从而被黑客攻击,导致某些服务不可用,严重的话还可能导致利用某些服务的漏洞获取到服务器的root权限。

为了消除这些安全问题,最好的做法就是不在公网上暴露任何端口,但是这样带来的问题是,从公司内网如何正常访问这些服务呢?

答案就是SSH反向代理。

二 什么是SSH反向代理?

先说说什么是代理,源服务器由于各种原因无法访问目标服务器提供的服务,但是存在一个agent服务器,源服务器可以访问它,它可以访问目标服务器,那么源服务器的消息发给他,它在把请求转发给目标服务器,就间接的实现了源服务器访问目标服务器的目的。

这就是代理,也是一般所说的正向代理,正向代理一般是代理客户端(源服务器,信息的请求者)。这时候,在公网上发送的信息的请求者就是代理服务器的身份,而不是真正客户端的身份。好处显而易见,隐藏客户端的身份。

img

那什么是反向代理呢?

百度百科:当一个代理服务器能够代理外部网络上的主机,访问内部网络时,这种代理服务的方式称为反向代理服务。

这句话不太好理解,应该改一改:“当一个代理服务器能够代理外部网络上的主机,使得内部网络可以访问时(不通过公网IP),这种代理服务的方式称为反向代理服务。”

img

image

例如下面的场景:公司局域网内的服务器(例如172.16.1.1)可以访问公网,公网无法访问它,如果不在公司的出口防火墙上暴露端口,那么在你的家里(192.168.0.100)(具有一个出口公网IP的局域网,已经将客户机(192.168.0.100的端口通过NAT(家用路由器就有这个功能))映射到出口公网IP的一个端口上),这时候,公司局域网的服务器是可以访问家用出口公网IP的,这时候,通过一个反向代理,将服务器的服务端口代理到家用出口公网IP上的绑定端口上,这时候,在你家里,就可以像访问本机服务一样访问公司内部服务器提供的服务了。

下面一张图来说明:

img

image

反向代理,将服务器的端口代理到外部网络中,在外部网络中可以直接访问,隐藏了真实的服务端,在外部网络中访问时候,就像访问同一网络中的服务一样。

上面的图中,通将MySQL的3306端口通过SSH反向代理到家庭局域网的主机上,在家庭主机上,可以像访问本机服务一样访问公司内部的MySQL服务。

三 SSH反向代理的好处是什么?

SSH会话通过建立一个加密的通道,在数据入口(SSH客户端)处进行加密,在出口(SSH服务端)进行解密,实现了比较安全的会话机制。

SSH还支持转发TCP、UDP的消息,这样其他依赖于TCP、UDP的服务均可以利用SSH代理来实现转发访问。

即使我们使用不安全的协议,例如FTP、TELNET等明文通讯协议,也不怕信息泄露,因为这一切都是发生在SSH建立起的加密隧道中的,无法被轻易窃取。

四 SSH反向代理的原理是什么?

端口转发。

将某个端口接收到的请求转发到指定的端口上。

SSH反向代理时,服务端主动发起SSH连接到代理服务器,将代理服务器指定端口接受到的请求通过SSH隧道转发到服务端的指定的端口上。对于原有的通讯是透明的,SSH相当于高速公路,不管你是什么车,上高速之前跟下高速之后都是一样的,告诉公路保证了你的告诉通行。

五 实际案例详解

公司在阿里云主机上购买了多台ECS主机部署了微服务,某些服务需要在公司内网进行访问。但是在防火墙了打个洞(开个端口)又带来了极大的安全风险。所以决定利用SSH的安全特性采用SSH反向代理的形式访问服务。

ECS主机可以访问公网,公网不可以访问ECS主机。ECS主机的内网IP是192.168.0.26.

公司内部有一个机器,将SSH服务的22端口映射到了公司出口公网IP的12022端口上,因此ECS主机可以SSH到这台主机。

这时候通过下面的命令在ECS主机上启动SSH反向代理:

ssh -NfR 4242:localhost:32541 [email protected] -p10022

上面的命令,是将ECS主机上的32541端口与远端(公司内网机器)的4242端口绑定起来。这样发送给公司内部机器4242端口的请求都将转发到服务端的32541端口上。

但是这样子,4242端口只是监听在127.0.0.1上,显然我们还需要从公司内部的其他机器访问,所以这个端口需要监听在内网IP上,这时候又利用到了SSH端口转发的功能:

ssh -N -f -L 10.0.0.56:4242:127.0.0.1:4242 [email protected]

上面的命令是将10.0.0.56:4242接收到的请求转发哦到本机的127.0.0.1:4242端口上,4242端口恰好是SSH反向代理监听的端口,随后请求就会被转发到ECS主机上的32541端口,这样在公司内部就实现了访问ECS主机服务。同时特避免了在防火墙上打洞。

这样子如果ECS主机上的SSH进程停止了,那么从公司内部就无法访问了,可以利用autossh的自动重连机制来避免这种情况。

在ECS主机上安装autossh程序后,通过下面的命令启动:

autossh -M 7281 -fCNR 3306:localhost:3306 [email protected]

-M参数理解为心跳即可。当心跳不通时,就会重连。当然也需要端口再转发下。否则只能从127.0.0.1访问。

再将上面的命令放入脚本中,开机启动即可。就能够实现从公司内部稳定持续访问ECS主机服务了。

SSH参数说明:

  • -N:指定这个SSH连接只进行端口消息转发,不执行任何SSH远程命令;
  • -L:指定本地监听的地址和端口;
  • -f: 这个SSH会话放入后台运行,不加这个参数的话,当退出当前SSH -L指定的终端时,端口转发进程就结束了,端口转发送也就结束了。所以务必要加上-f参数。