加强内网穿透的安全性
一、为什么需要加强安全性
内网穿透实际上是将内网机器的某些端口暴露到公网。普通的端口暴露出来并没有太大危害,比如网站或者某些后台服务的端口。而如果把ssh、nfs、samba或者数据库的一些端口暴露出来就会比较危险了。在公网上,有非常多的攻击,最简单的就是端口扫描后进行暴力破解。这些端口一旦公开在公网上,理论上被成功暴力破解攻破只是时间问题。
通常,我们可以通过封锁IP的方式来解决这种暴力攻击。但是,如果使用了内网穿透。便无法封锁IP,因为在可以识别攻击行为的地方,并不知道真实的攻击者IP。
内网穿透的访问链路如下:
从链路图可以看出,内网电脑可以识别出暴力攻击行为。但是,它只知道是内网穿透客户端
访问过来的,并不清楚攻击者的真实IP地址。实际上,连内网穿透客户端
也不知道,只有内网穿透服务端
才知道。而无论是内网穿透客户端
还是内网穿透服务端
都不清楚当前用户是否是攻击者。
二、通过白名单加强内网穿透的安全性
首先,我们要搞清楚,哪些端口是开放给所有人访问的,哪些端口是单独给特定的少数人使用的。通常而言,ssh、nfs、samba或者数据库的端口,这些高危端口正好是给特定少数人使用的。所以,我们可以针对这些端口设计一个白名单。只有在白名单中的IP才可以访问这些端口。于是,这些端口也就安全了。链路图变为:
接下来,有一个问题,那就是怎么维护白名单。如果手动维护白名单,成本会比较高。尤其是,用户的IP随时可能发生变动。当无法访问的时候再被动的将用户的IP加入到白名单,肯定会非常麻烦不说,还影响用户的正常使用,效率底下。所以,我们需要一个免维护的白名单。要想做到免维护,最好的办法就是授权用户自己去维护白名单。比如,在访问高危端口前,必须先访问某个低危端口提供的接口服务。在这个接口服务中,将用户的IP地址自动加入到白名单。加入白名单以后,只会在较短时间内有效,一旦超时就会从白名单中删除。
首先,由于低危端口的网址是不公开的(将IP加入白名单这个动作),而且与访问高危端口并没有直接的关联关系。所以,攻击者无法进行无脑暴力攻击。
其次,即使有人专门尝试攻击我们的服务器。比如,由于某种原因,我们需要公开低危端口的网址。那么,只需要对低危端口的访问进行安全加固就可以了。
注意:
- 白名单仅在建立连接的阶段有效。连接被建立后,就不需要白名单了。用户的IP也就可以从白名单中移除了。所以,超时时间可以设置的比较短。
- 用户IP加入白名单这个行为可以是自动发生,完全不需要人工参与。即使是用户,也可以做到完全不知道有加白名单这个过程。
三、实现方法
3.1 白名单服务程序
可以使用python来实现白名单服务程序,比较简单,不到50行就可以实现所有的逻辑。
from flask import Flask, request,abort, make_response
import json
import datetime
app = Flask("white_list_demo")
white_list = {}
@app.route("/white_list/<int:id>/<string:key>", methods=['PUT'])
def add_to_white_list(id, key):
# TODO: check id and key
now = datetime.datetime.now()
white_list[request.remote_addr] = now
for ip in white_list.keys():
if (now - white_list[ip]).seconds > 60:
del white_list[ip]
return 'sucess'
@app.route("/white_list", methods=['POST'])
def is_in_white_list():
op = request.args.get('op')
data = {
"reject": False,
"unchange": True,
}
while True:
if op != "NewUserConn":
break
req = request.json()
ip = req["content"]["remote_addr"].split(":")[0]
if ip not in white_list:
data["reject"] = True
data["reject_reason"] = "not found"
break
response = make_response(json.dumps(data))
response.mimetype = 'application/json'
return response
if __name__=='__main__':
app.run(host="127.0.0.1", port=5000)
3.2 内网穿透服务器配置
以frp为例,下面是frps的配置文件:
bindPort = 7900
[[httpPlugins]]
name = "white-list"
addr = "http://127.0.0.1:5000"
path = "/white_list"
ops = ["NewUserConn"]