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

*本文原创作者: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模块执行阶段如下图:

我们这次要实现的是服务器响应体敏感信息的记录,只需要用到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原创奖励计划,未经许可禁止转载

原文发布于微信公众号 - FreeBuf(freebuf)

原文发表时间:2018-08-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏非典型程序猿

Golang任务队列machinery使用与源码剖析(一)

异步任务,是每一位开发者都遇到过的技术名词,在任何一个稍微复杂的后台系统中,异步任务总是无法避免的,而任务队列由于其松耦合、易扩展的特性,成为了实现异步任务的可...

1.7K100
来自专栏FreeBuf

如何使用Tokenvator和Windows Tokens实现提权

今天给大家介绍的是一款名叫Tokenvator的工具,该工具采用.NET开发,可用于在Windows系统中提权。

12500
来自专栏安富莱嵌入式技术分享

【安富莱】【RL-TCPnet网络教程】第11章 RL-TCPnet调试方法

本章节为大家讲解RL-TCPnet的调试方法,RL-TCPnet的调试功能其实就是通过串口打印实时监控运行状态。而且RL-TCPnet的调试设置比较简单,因为官...

11760
来自专栏黑泽君的专栏

day69_淘淘商城项目_02

  由于淘淘商城是基于soa的架构,表现层和服务层是不同的工程。所以要实现商品列表查询需要两个系统之间进行通信。   如何实现远程通信?

38120
来自专栏Janti

记一次内存溢出的分析经历——thrift带给我的痛orz

说在前面的话 朋友,你经历过部署好的服务突然内存溢出吗? 你经历过没有看过Java虚拟机,来解决内存溢出的痛苦吗? 你经历过一个BUG,百思不得其解,头发一根一...

55180
来自专栏喔家ArchiSelf

嵌入式Linux的网络连接管理

连接管理器(ConnMan)是一个连接管理守护进程 , 用于管理运行 Linux 操作系统中设备的互联网连接。 它以快速、连贯、同步的方式对不断变化的网络条件提...

44320
来自专栏Spark学习技巧

分布式开放消息系统(RocketMQ)的原理与实践

30530
来自专栏H2Cloud

ffrpc-c++进程间(服务器端、客户端)通信框架

FFRPC github 地址 https://github.com/fanchy/FFRPC FFRPC 已经陆陆续续开发了1年,6月6日这天终于完成了我比较...

43140
来自专栏Golang语言社区

PHP调用Go服务的正确方式 - Unix Domain Sockets

作者:枕边书 链接:http://www.cnblogs.com/zhenbianshu/p/7265415.html 來源:博客园 问题 可能是由于经验太少,...

47690
来自专栏微服务生态

论代码级性能优化变迁之路(二)

在上一篇我们主要介绍了所遇到问题的五点,那么今天接下来讨论剩下的问题,我们先再回顾一下之前讨论的问题:

8820

扫码关注云+社区

领取腾讯云代金券