FRP代理及其在数据库安全上的实践

1 代理

现如今的互联网世界里,代理服务已经十分常见,它通常作为一个第三方或者说中转站角色替代用户取得信息或者服务。

根据代理对象的不同,代理服务可以分为正向代理和反向代理。

1.1 正向代理

我们通常所说的代理一般都指的是正向代理,正向代理的是客户端或者说访问者。如下图所示,在特定网络环境中,客户端直接访问目标服务器会被限制,如果有另外一台可以直接访问到目标服务器,且客户端也可以访问到这台服务器,那么就可以以这台服务器作为代理服务器向目标服务器发起访问,当目标服务器收到访问请求时,并不会获知访问的真正发起者,只会认为是代理服务器发来的请求,返回的消息也是通过代理服务器发送给客户端。

这整个过程我们可以用一个通俗的例子来类比:我们想要像土豪舅舅借钱,但是土豪舅舅觉得我们太年轻,怕我们借钱胡来就不想借。这时候我们找上了外婆,由外婆去问土豪舅舅借钱,然后我们从外婆手里拿到了钱。在整个借钱过程中,“我”就是这个发起访问的客户端,外婆就是这个正向代理,舅舅就是目标服务器,舅舅并不知道实际上还是我这个外甥在借钱,他只知道钱给了外婆,但是钱还是到了我们手上。

Fiddler、mitmproxy抓包,代理ip网络爬虫等应用就是基于正向代理。

1.2 反向代理

正向代理代理的是客户端,与之相反的反向代理代理的就是服务器端,客户端也并不知道真正访问的服务器时哪一台。反向代理在负载均衡等功能实现上有很好的应用,如下图所示,客户端向代理服务器发起请求,代理服务器接收到请求之后判断哪台目标服务器处理当前请求最合适,然后将请求转发该目标服务器进行处理,最后返回的消息也是再次通过代理服务器发送给客户端。在这整个过程中,客户端只知道它的请求发送给了代理服务器,并不知道真正处理请求的是谁。

反向代理在大型web中有广泛应用,以淘宝为例,如此庞大的一个网站一台服务器肯定承担不了,但我们通过淘宝网购物时,只需要访问https://www.taobao.com即可,我们并不关心处理我们访问请求的服务器是哪一台,只要能访问淘宝购物即可。

反向代理的应用有很多,例如Ngrok、Nginx,还有本文主要要说的FRP。

2 frp代理

FRP,Fast Reverse Proxy,从英文名上可以看出宗旨是建立一种高性能的反向代理应用,采用GO语言开发,能在多种平台运行,支持 TCP、UDP、HTTP、HTTPS 等多种协议类型。目前,FRP在内网穿透,对外网提供服务有着极其广泛的应用。

2.1 内网穿透

是否遇到过下面两种困境:

(1)我们平台在外出差,亦或者回到家中后临时工作需要访问公司服务器,但是却苦于所使用的的网络环境与公司服务器不在同一局域网内,导致无法访问。

(2)在公司办公,突然需要访问一下家里电脑的某个服务(例如数据库),但是家里的电脑却没有固定IP导致没法访问。

上面两种困境大多数喜欢折腾电脑的人都遇到过,如果你还没有解决,FRP提供的内网穿透就是一个不错的选择。

FRP源码发布在 github 上面,同时我们可根据自身系统平台在其 release 页面下载,直接解压即可使用。

注意,在使用前必须有一台有固定公网IP的机器作为代理服务器(假设公网ip为90.190.80.10),然后配置防火墙对外开放两个端口(假设为7000,6000端口)。

我们以外网机器访问内网服务器上的mongodb数据为例,搭一个内网穿透应用,结合应用来理解原理。

首先配置代理服务器,新建一个frps_mongodb.ini文件,写入一下内容:

[common]
bind_port = 7000

通过FRP的frps命令启动代理服务:

$ ./frps -c frps_mongodb.ini

接下来配置内网中需要被访问机器,新建一个frpc_mongodb.ini文件,写入一下内容:

[common]
server_addr = 90.190.80.10
server_port = 7000

[mongodb]
type = tcp
local_ip = 127.0.0.1
local_port = 27017
remote_port = 6000

启动客户端代理:

$ ./frpc -c frpc_mongodb.ini

完成上述所有操作后,在外网的机器已经可以通过90.190.80.10机器的6000端口来访问内网机器27017端口对应的mongodb数据库了。

上述过程中,FRP工作流程如下图所示:

到了现在,外网已经可以通过访问到位于局域网内部的数据库了,不过,这样安全吗?

3 stcp代理与数据库安全

3.1 stcp代理

我们知道,对于重要数据库而言,是绝不会暴露给外网的,如上一节的通过内网穿透,将内网中的mongodb数据库提供给外网访问的方式,任何人只要知道了代理服务器ip和端口,都可以访问这个mongodb,这对数据库来说是非常危险的。

惊喜的是,FRP中提供了一种不错的解决方案——stcp代理。

与上面介绍过的普通代理方式不同,stcp代理要求在访问端也运行一个FRP,在通过代理服务器进行通话前,代理服务器将会对比访问端和被访问端的sk口令,只有当两者的sk口令一致时,才允许转发信息,有效避免通过FRP内网穿透攻击到数据库。

使用stcp代理方式时,服务器端配置与上面一样,不再多说,关键在于访问端配置和内网被访问端机器配置。

内网中的被访问端配置,新建frpc_mongodb.ini,内容如下:

[common]
server_addr = 90.190.80.10
server_port = 7000
[mongodb]
# 指定代理类型
type = stcp
local_ip = 127.0.0.1
local_port = 27017
sk = password123

启动被访问端frp代理服务:

$./frpc -c frpc_mongodb.ini

如果只需要共一台机器访问,那么在该机器上新建配置文件frpc_mongo_viditor.ini,内容如下:

[common]
server_addr = 90.190.80.10
server_port = 7000

[mongodb_visitor]
type = stcp
# stcp 的访问者
role = visitor
# 要访问的 stcp 代理的名字,也就是上面frpc_mongodb.ini中配置的[mongodb]
server_name = mongodb
# 下面的sk口令必须与上面配置的sk一直才能访问
sk = password123
# 绑定本机端口用于访问 mongodb服务
bind_addr = 127.0.0.1
bind_port = 6000

启动frpc服务:

$./frpc -c frpc_mongodb_viditor.ini

代理服务器、访问端、内网被访问端三者的代理服务都开启后,那么访问端局域网内所有机器就可以通过192.168.0.10机器的6000端口访问另一端内网中的mongodb数据库了,而在其他没有开启frp代理或者sk口令不正确的是访问不了的。

3.2 代理云服务器数据库

明白了stcp代理方式后,我们就可以扩展一下这种代理方式的的用途。

在很多时候,数据库是部署在云服务器上的,在某些情况下,这些数据库不得不提供给外界访问,但如果直接开放端口,将数据库暴露给外网,却又给数据库带来安全隐患。

此时也可以用stcp代理来解决这一问题。

在上文介绍正向代理和反向代理时说过,经过代理服务器转发后,服务器只会认为是代理服务器在发起访问。回到数据库的问题,以mongodb数据库为例,数据库配置为绑定本机IP127.0.0.1和27017端口,那么一切来自其他机器的访问都会被拒绝,但却不会拒绝来自本机其他端口的访问。所以,解决上述问题的思路就是使用FRP的stcp代理方式来代理本机数据库服务端口,那么其他机器只要具有正确的sk口通过stcp代理方式就可以连接上数据库。

因为是本机代理本机,所以我们可以修改一下上面的配置,将服务器IP地址改为127.0.0.1,对于frps,配置文件为frps_mongodb.ini,内容如下:

[common]
server_addr = 127.0.0.1
server_port = 7000

被访问端也是本机,只不过也是在云服务器上启动,配置文件为frpc_mongodb.ini,内容如下:

[common]
server_addr = 127.0.0.1
server_port = 7000
[mongodb]
# 指定代理类型
type = stcp
local_ip = 127.0.0.1
local_port = 27017
sk = password123

假设访问端代理服务部署在局域网IP为192.168.0.10服务器上,如果需要让局域网内所有机器都能够使用代理来连接数据库,在该机器上新建配置文件frpc_mongodb_visitor.ini,内容如下:

[common]
server_addr = 90.190.80.10
server_port = 7000

[mongodb_visitor]
type = stcp
# stcp 的访问者
role = visitor
# 要访问的 stcp 代理的名字
server_name = mongodb
sk = password123
# 绑定本机局域网ip、端口,可供局域网内所有机器访问
bind_addr = 192.168.0.10
bind_port = 6000

4 总结

FRP提供了一种便捷的方式实现内网穿透,使得即是在外网也能够使用到局域网内部的服务,但数据诚可贵,即使FRP中提供了stcp这种安全的代理方式,谁又能保证使用这种方式后会不会代理新的隐患,慎思之,笃行之。