67

打造基于Nginx的敏感信息泄露检测系统

 5 years ago
source link: http://www.freebuf.com/articles/web/179848.html?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

*本文原创作者:f4ckbaidu,本文属FreeBuf原创奖励计划,未经许可禁止转载

0、环境说明:

注意:本文所有的代码都放在/data/code下面

如路径变化则需要修改test.conf中标红的路径参数:

操作系统:CentOS 7 Minimal

OpenResty版本:1.13.6.2( https://openresty.org/cn/download.html

Splunk Free: https://download.splunk.com/products/splunk/releases/7.1.2/linux/splunk-7.1.2-a0c72a66db66-linux-2.6-x86_64.rpm

1、需求说明

在甲方的小伙伴一定会碰到这样的问题:

日了狗的开发总是不把应用/数据库的详细错误信息隐藏,妈蛋要是哪天出个error-based sqli岂不是倒霉了?如何主动检测敏感信息泄露然后拿去使劲怼开发呢?

答案当然是用春哥的神器OpenResty(继承了Nginx、Nginx lua等一堆模块的合体)

2、具体实现

Nginx Lua模块执行阶段如下图:

QFbiAf2.jpg!web

我们这次要实现的是服务器响应体敏感信息的记录,只需要用到body_filter(响应体处理)和log(日志记录)两个阶段处理,流程如下:

body_filter阶段匹配resp_body–>通过ngx.ctx跨阶段传日志到log阶段–>log阶段向Splunk发送日志–>Splunk统计、告警、分析

body_filter阶段代码如下:(body_filter.lua)

local resp_body = ngx.arg[1] --获取响应体
local eof = ngx.arg[2]
local ctx_log = {} --日志table

local regex = [[You have an error in your SQL syntax]] --匹配的敏感内容

local m = ngx.re.match(resp_body, regex, 'jio') --对响应体做正则匹配

if m then --如果匹配到敏感信息
	ctx_log.rule_match = m[0] --将匹配内容写入日志
	ctx_log.Request_line = ngx.var.request --记录请求URL,包括GET参数
	ctx_log.Request_headers = ngx.req.get_headers() --记录请求头部
	ngx.ctx.log = ctx_log --日志赋值给跨阶段的ngx.ctx.log
end

log阶段代码如下:(log.lua)

local logger = require "socket" --加载logger socket库
local cjson = require "cjson.safe" --加载cjson库

if not logger.initted() then --初始化logger
	local ok,err = logger.init{
			host = "127.0.0.1", --splunk IP
			port = 8888,		--splunk端口
			sock_type = "tcp",	--日志socket类型
			flush_limit = 1,
			}
	if not ok then --初始化失败处理
		ngx.log(ngx.ERR,"failed to initialize the logger: ",err)
		return
	end
end

local log = ngx.ctx.log --接收ngx.ctx.log跨阶段传过来的日志信息

if type(log) == "table" then --判断日志不为空则记录
	local bytes, err = logger.log(cjson.encode(log) .. "\r\n")
	if err then
		ngx.log(ngx.ERR, "failed to log message: ", err)	
	end
end

然后在nginx的http级别include test.conf即可,test.conf内容如下:

lua_package_path '/data/code/?.lua;;';
body_filter_by_lua_file /data/code/body_filter.lua;
log_by_lua_file /data/code/log.lua;
lua_code_cache on;

zMneuaz.jpg!web

我这里使用dvwa的sqli部分做实验,用来记录服务器返回的MySQL错误信息:

我这里的测试架构是:nginx(反向代理)–>httpd + php(dvwa)

输入单引号让服务器报MySQL错误

z6ruq2f.jpg!web

QvINBr7.jpg!web

然后就能在splunk里看到日志了:

如下图所示,可以看到日志记录了客户端的请求头部(Request_headers、Request_line)以及服务器的相应体匹配数据(rule_match)

PS:如果要记录用户的POST请求体则会变得更复杂,需要在access阶段做处理,后面的文章里再说

zQ7nInZ.jpg!web

Splunk需要注意的地方:

需要编辑props.conf以免在日志过多的时候Splunk自动把多行Json格式日志合并

vim /opt/splunk/etc/system/local/props.conf

加入以下内容:

[_json]  #这个是sourcetype
SHOULD_LINEMERGE = false  #告诉Splunk不自动合并行

3、参考:

春哥的nginx lua模块:

https://github.com/openresty/lua-nginx-module

OpenResty logger socket模块:

https://github.com/cloudflare/lua-resty-logger-socket

OpenResty最佳实践:

https://moonbingbing.gitbooks.io/openresty-best-practices/lua/main.html

*本文原创作者:f4ckbaidu,本文属FreeBuf原创奖励计划,未经许可禁止转载


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK