如果用Node.JS做Web服务,很多时候是会选择Express的。

本文,将展示如何如何实现一个WAF中间件。

WAF有什么用?

WAF即Web Application Firewall,Web应用防火墙,防攻击、防黑客的。

小提示:npm上,目前还没有专业的express中间件WAF,这可是稀缺的技术!

先看完整示例代码:

var express = require('express');
var app = express();

//当访问根目录时触发
app.get('/', function (req, res) {
   res.send('Hello Jshaman.com');
})

//WAF中间件
app.use(function(req, res, next) {
    var path = req.url;
    console.log(path);
    if(waf_detect(path) == false){
        next();
    }
    //console.log(req.cookies);
    //console.log(req.headers['user-agent']);
});

//使用正则表达式,检测字符串是否含有攻击特征,检测到攻击特征返回true,没检测到返回false
function waf_detect(str_to_detect){

    var regexp_rule =[
        /select.+(from|limit)/i,
        /(?:(union(.*?)select))/i,
        /sleep\((\s*)(\d*)(\s*)\)/i,
        /group\s+by.+\(/i,
        /(?:from\W+information_schema\W)/i,
        /(?:(?:current_)user|database|schema|connection_id)\s*\(/i,
        /\s*or\s+.*=.*/i,
        /order\s+by\s+.*--$/i,
        /benchmark\((.*)\,(.*)\)/i,
        /base64_decode\(/i,
        /(?:(?:current_)user|database|version|schema|connection_id)\s*\(/i,
        /(?:etc\/\W*passwd)/i,
        /into(\s+)+(?:dump|out)file\s*/i,
        /xwork.MethodAccessor/i,
        /(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\(/i,
        /\<(iframe|script|body|img|layer|div|meta|style|base|object|input)/i,
        /(onmouseover|onmousemove|onerror|onload)\=/i,
        /javascript:/i,
        /\.\.\/\.\.\//i,
        /\|\|.*(?:ls|pwd|whoami|ll|ifconfog|ipconfig|&&|chmod|cd|mkdir|rmdir|cp|mv)/i,
        /(?:ls|pwd|whoami|ll|ifconfog|ipconfig|&&|chmod|cd|mkdir|rmdir|cp|mv).*\|\|/i,
        /(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\//i
    ];

    for(i=0; i< regexp_rule.length; i++){
        if(regexp_rule[i].test(str_to_detect) == true){
			console.log("attack detected, rule number:", "("+i+")", regexp_rule[i]);
			return true;
        }
    }
    return false;
}

var server = app.listen(8000, function () {
   var host = server.address().address
   var port = server.address().port
   console.log(host, port);
})
 

本示例,是一个带有WAF功能的Web应用。

内置的中间件部分,实现WAF的防护功能:

//WAF中间件
app.use(function(req, res, next) {
    var path = req.url;
    console.log(path);
    if(waf_detect(path) == false){
        next();
    }
    //console.log(req.cookies);
    //console.log(req.headers['user-agent']);
});

即,对发起的请求进行过滤,判断请求中是否有恶意行为。如果有,则不让中件间进行next(),请求也就被中断,达到防止攻击者入侵的目的。

WAF防护规则

攻击检测使用的是正则表达式,这是WAF常用的攻击检测方式。

这套规则来自ShareWAF,ShareWAF是专业、强大的WAF商业产品。

//This rule from:www.sharewaf.com
var regexp_rule =[
        /select.+(from|limit)/i,
        /(?:(union(.*?)select))/i,
        /sleep\((\s*)(\d*)(\s*)\)/i,
        /group\s+by.+\(/i,
        /(?:from\W+information_schema\W)/i,
        /(?:(?:current_)user|database|schema|connection_id)\s*\(/i,
        /\s*or\s+.*=.*/i,
        /order\s+by\s+.*--$/i,
        /benchmark\((.*)\,(.*)\)/i,
        /base64_decode\(/i,
        /(?:(?:current_)user|database|version|schema|connection_id)\s*\(/i,
        /(?:etc\/\W*passwd)/i,
        /into(\s+)+(?:dump|out)file\s*/i,
        /xwork.MethodAccessor/i,
        /(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\(/i,
        /\<(iframe|script|body|img|layer|div|meta|style|base|object|input)/i,
        /(onmouseover|onmousemove|onerror|onload)\=/i,
        /javascript:/i,
        /\.\.\/\.\.\//i,
        /\|\|.*(?:ls|pwd|whoami|ll|ifconfog|ipconfig|&&|chmod|cd|mkdir|rmdir|cp|mv)/i,
        /(?:ls|pwd|whoami|ll|ifconfog|ipconfig|&&|chmod|cd|mkdir|rmdir|cp|mv).*\|\|/i,
        /(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\//i
    ];

规则逻辑暂且不详细探讨,因为它是正则表达式,如果详细讲述起来,恐怕得另多写三五篇文章了。

执行效果:

模拟访问发起攻击:

http://127.0.0.1:8000/index.html

即在url中传入select*from admin语句,这是一句常见的SQL注入攻击语句。

可以看到,网站无法打开。在后台输出了拦截信息,并提示出触发了哪条WAF防护规则。

本文只做演示,仅检测了url路径。

那么本代码是可以括展的,可以检测cookie、user-agent、post数据等常见攻击点。

写成一个Express模块是完全可以的。