nodejs http-proxy 开发反向代理服务器,防火墙,过滤常见的web渗透
程序员文章站
2022-06-29 07:58:10
事出有因 最近web系统引来了黑客的攻击,经常被扫描,各种漏洞尝试。 分析攻击日志,有几种常见的攻击手段: 上传webshell 远程执行命令漏洞 sql注入 xxs 攻击 试探各种开源框架爆出来的漏洞 分析攻击信息的特点 说白了就是采用web渗透技术,利用http请求,黑客想尽办法,在http h ......
事出有因
最近web系统引来了黑客的攻击,经常被扫描,各种漏洞尝试。
分析攻击日志,有几种常见的攻击手段:
- 上传webshell
- 远程执行命令漏洞
- sql注入
- xxs 攻击
- 试探各种开源框架爆出来的漏洞
分析攻击信息的特点
说白了就是采用web渗透技术,利用http请求,黑客想尽办法,在http header ,body,等部分植入非法的命令,非法字符常见的有:exe,cmd,powershell,download,select,union,delete等等。
解决问题思路
- 我们能不能开发个代理服务器,来分析http请求header,body里面的信息,如果有非法字符,就截断,拒绝服务。
- 配置允许请求的白名单,拒绝非法url.
网络拓扑
http proxy 拦截非法请求,拒绝服务。
技术选型
常见的代理服务器有nginx,apache,不知道这2个代理服务器能不能灵活的配置,过滤,转发,没有深入了解。
因此选用nodejs http-proxy。
nodejs优点
- 轻量级
- 快速部署
- 灵活开发
- 高吞吐,异步io
编码实现逻辑图
绝对干货,分享代码
代码依赖
- http-proxy 1.17.0
https://github.com/nodejitsu/node-http-proxy 代码地址 - "colors": "~0.6.2",
var util = require('util'), colors = require('colors'), http = require('http'), httpproxy = require('./node_modules/http-proxy'); fs = require("fs"); var welcome = [ '# # ##### ##### ##### ##### ##### #### # # # #', '# # # # # # # # # # # # # # # # ', '###### # # # # ##### # # # # # # ## # ', '# # # # ##### ##### ##### # # ## # ', '# # # # # # # # # # # # # ', '# # # # # # # # #### # # # ' ].join('\n'); date.prototype.format = function(fmt) { //author: meizz var o = { "m+": this.getmonth() + 1, //月份 "d+": this.getdate(), //日 "h+": this.gethours(), //小时 "m+": this.getminutes(), //分 "s+": this.getseconds(), //秒 "s": this.getmilliseconds() //毫秒 }; if (/(y+)/.test(fmt)) fmt = fmt.replace(regexp.$1, (this.getfullyear() + "").substr(4 - regexp.$1.length)); for (var k in o) if (new regexp("(" + k + ")").test(fmt)) fmt = fmt.replace(regexp.$1, (regexp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); return fmt; } // 非法字符 var re = /php|exe|cmd|shell|select|union|delete|update|insert/; /** 这里配置转发 */ var proxypassconfig = { "/hello": "http://www.qingmiaokeji.cn ", "/": "http://127.0.0.1/" } var logrootpath ="g:/httpproxy/"; console.log(welcome.rainbow.bold); function getcurrentdayfile(){ // console.log(logrootpath+"access_"+(new date()).format("yyyy-mm-dd")+".log"); return logrootpath+"access_"+(new date()).format("yyyy-mm-dd")+".log"; } // // basic http proxy server // var proxy = httpproxy.createproxyserver({}); var server = http.createserver(function (req, res) { appendlog(req) var postdata = ""; req.addlistener('end', function(){ //数据接收完毕 console.log(postdata); if(!isvalid(postdata)){//post请求非法参数 invalidhandler(res) } }); req.addlistener('data', function(postdatastream){ postdata += postdatastream }); var result = isvalid(req.url) //验证http头部是否非法 for(key in req.headers){ result = result&& isvalid(req.headers[key]) } if (result) { var patternurl = urlhandler(req.url); console.log("patternurl:" + patternurl); if (patternurl) { proxy.web(req, res, {target: patternurl}); } else { nopattern(res); } } else { invalidhandler(res) } }); proxy.on('error', function (err, req, res) { res.writehead(500, { 'content-type': 'text/plain' }); res.end('something went wrong.'); }); /** * 验证非法参数 * @param value * @returns {boolean} 非法返回false */ function isvalid(value) { return re.test(value) ? false : true; } /** * 请求转发 * @param url * @returns {*} */ function urlhandler(url) { var tempurl = url.substring(url.lastindexof("/")); return proxypassconfig[tempurl]; } function invalidhandler(res) { res.writehead(400, {'content-type': 'text/plain'}); res.write('bad request '); res.end(); } function nopattern(res) { res.writehead(404, {'content-type': 'text/plain'}); res.write('not found'); res.end(); } function getclientip(req){ return req.headers['x-forwarded-for'] || req.connection.remoteaddress || req.socket.remoteaddress || req.connection.socket.remoteaddress; } function appendlog(req) { console.log("request url:" + req.url); var logdata = (new date()).format("yyyy-mm-dd hh:mm:ss")+" "+getclientip(req)+" "+req.method+ " "+req.url+"\n"; fs.exists(logrootpath,function(exists){ if(!exists){ fs.mkdirsync(logrootpath) } fs.appendfile(getcurrentdayfile(),logdata,'utf8',function(err){ if(err) { console.log(err); } }); }) } console.log("listening on port 80".green.bold) server.listen(80);
思路扩展
- 拦截非法字符后可以发邮件通知管理员
- 可以把日志发送到日志系统,进行大数据分析
- 增加频繁访问,拒绝ip功能。 可以利用redis 过期缓存实现。
上一篇: __str__,__repr__