*本文原创作者:f4ckbaidu,本文属FreeBuf原创奖励计划,未经许可禁止转载
0、环境说明:
注意:本文所有的代码都放在/data/code下面
如路径变化则需要修改test.conf中标红的路径参数:
操作系统:CentOS 7 Minimal
OpenResty版本:1.13.6.2(https://openresty.org/cn/download.html)
1、需求说明
在甲方的小伙伴一定会碰到这样的问题:
日了狗的开发总是不把应用/数据库的详细错误信息隐藏,妈蛋要是哪天出个error-based sqli岂不是倒霉了?如何主动检测敏感信息泄露然后拿去使劲怼开发呢?
答案当然是用春哥的神器OpenResty(继承了Nginx、Nginx lua等一堆模块的合体)
2、具体实现
Nginx Lua模块执行阶段如下图:
我们这次要实现的是服务器响应体敏感信息的记录,只需要用到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;
我这里使用dvwa的sqli部分做实验,用来记录服务器返回的MySQL错误信息:
我这里的测试架构是:nginx(反向代理)-->httpd + php(dvwa)
输入单引号让服务器报MySQL错误
然后就能在splunk里看到日志了:
如下图所示,可以看到日志记录了客户端的请求头部(Request_headers、Request_line)以及服务器的相应体匹配数据(rule_match)
PS:如果要记录用户的POST请求体则会变得更复杂,需要在access阶段做处理,后面的文章里再说
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原创奖励计划,未经许可禁止转载