为什么需要业务隐身
部署完本文所述的业务隐身方案后,在腾讯云一台普通服务器半个月收到了来自 224 个不同 ip 的访问请求
在网络世界中,各种匿名爬虫的数量之大超乎想象,它们不知疲倦的搜集着每一台主机的信息
一旦被它们发现漏洞或后门,被用来当肉鸡挖矿事小,数据泄漏也不是不能忍,
可万一它们搞什么违法活动是真的会殃及自身的。
对于业务方来说,我们很难做到时刻保持警惕,也难以时刻跟进最新安全资讯
一个简单而直接的需求就出现了:不让陌生人发现我们的系统
如何设计业务隐身
我们期望的业务隐身模块最好能满足以下特点
- 非侵入式
- 不需要对原业务系统做太大改造
- 不影响正常业务逻辑
- 成本可控
- 研发改造成本
- 运维成本
- 额外性能消耗
- 通用透明
- 不需要对每个业务系统做针对式改造
- 改造后逻辑对具体业务透明
设计方案
首先考虑通用性,如果需要方案对任意后端服务生效,就必须作用在通信链路上
通过中间件去验证请求方身份,然后再允许此次通信,否则需要具备阻断能力
高配方案
linux 内核提供了一个通用的包过滤框架 netfilter。
在流量包经过内核协议栈的时候会触发预先注册在 netfilter 的 hook 点。
- NF_IP_PRE_ROUTING
- NF_IP_LOCAL_IN
- NF_IP_FORWARD
- NF_IP_LOCAL_OUT
- NF_IP_POST_ROUTING
这里不多赘述细节了,因为一篇文章根本讲不完。
总之通过 netfilter 我们可以实现很多非常灵活的包校验逻辑,比如
- 区分通信端口和认证端口
认证端口负责完成一系列用户登录逻辑
通信端口则是正常的业务处理逻辑,如果用户 ip 没有认证过则拦截流量
- tcp/udp 内容校验
若客户端发过来的包里不符合特定格式,或不带特定 key 则自动丢包
经济方案
在绝大多数的服务器上都会部署一个 nginx 作为反向代理,因此本方案的通用性是足够好的
在 nginx 中,我们可以通过接入 lua 扩展来定制化请求校验逻辑(参见 openresty)
而且相比上述高配方案,这里校验 https 请求也变得更为简单
首先需要配置禁止 ip 直接访问,目的是屏蔽那些简单粗暴遍历 ip 的爬虫
1
2
3
4
5server {
listen 443 default_server;
server_name _;
return 444;
}然后配置定制化校验逻辑,比如这里校验请求头部必须带上时间戳
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26location / {
# deny anonymous request
access_by_lua_block {
local xtoken = ngx.req.get_headers()["Token"]
if not xtoken then
ngx.exit(ngx.HTTP_CLOSE)
end
local token = ""
if type(xtoken) == "string" then
token = xtoken
else
token = xtoken[1]
end
if not token then
ngx.exit(ngx.HTTP_CLOSE)
end
local t = tonumber(token)
if not t or math.abs(ngx.now()-t) > 600 then
ngx.exit(ngx.HTTP_CLOSE)
end
return
}
root html;
index index.html index.htm;
}
第二步的校验逻辑也可以改成其他自定义的 token,配合一些加密算法效果更好
完成以上两步后,除非其他人专门渗透你的服务器,否则完全不用担心被爬虫扫到
即使日后你使用的依赖库爆出惊天大漏洞,也可以放心不会被脚本小子乱打
后记
从没有绝对的安全
每种安全方案都只能解决一些特定场景的问题,业务隐身能非常好的避免供应链漏洞被暴露在公共网络下
对于防止漏洞被滥用,防止无意义流量嗅探有着较好的效果,但绝不意味着可以放松警惕
它非常适合那些「希望自己的服务只被正确的人用来做合适的事」的场景
附录
1 | worker_processes 2; |