NPM是Node的包管理工具,Node的所有三方模块,都在NPM上。

今天的文章,是重量级的。

展示如何写一个真正的模块,并发布到NPM,可以让他人使用自己的模块!

首先是模块。

要发布到NPM,模块本身真是够份量的,实现了某个功能,或能真正解决某些问题,或在某些场景下能帮到他人。

模块:express-waf-middleware

本文的模块,来之前于前面文章讲到过的一个思路:给express写一个WAF。

今天将此模块变为现实。

index.js

//waf rules
var regexp_waf_rule = require("./rule.js").regexp_waf_rule;

//detect with waf rules
function waf_detect(type,value,log){
    for(i=0; i< regexp_waf_rule.length; i++){
        if(regexp_waf_rule[i].test(value) == true){
           
            var detect_result = { 
                "Warn:": "Express-waf-middleware detected attack.",
                "Type:": type,
                "Value:": value,
                "Rule number:":i,
                "Rule:": regexp_waf_rule[i].toString()
            };

            //display log info
            if(log){
			    console.log(detect_result);
            }
            return detect_result;
        }
    }
    return false;
}

//export
module.exports = function(options = {url:1,cookies:1,userAgent:1,body:1,log:1}){
    return function(req,res,next){
        
        if(options.url){
            if(options.log){
                console.log("Request url detected")
            }
            var detect_result = waf_detect("url",req.url,options.log);
            if(  detect_result != false){
                res.status(404);
                res.send(detect_result);
            }
        }
        
        if(options.cookies){
            if(options.log){
                console.log("Request cookies detected")
            }
            var detect_result = waf_detect("cookies",req.cookies,options.log);
            if(  detect_result != false){
                res.status(404);
                res.send(detect_result);
            }
        }
        
        if(options.userAgent){
            if(options.log){
                console.log("Request user-agent detected")
            }
            var detect_result = waf_detect("userAgent",req.headers["user-agent"],options.log);
            if(  detect_result != false){
                res.status(404);
                res.send(detect_result);
            }
        }

        if(options.body){
            if(options.log){
                console.log("Request body detected")
            }
            var detect_result = waf_detect("userAgent",req.headers["user-agent"],options.log);
            if(  detect_result != false){
                res.status(404);
                res.send(detect_result);
            }
        }

        next();
    }    
}

模块根目录下index.js总是模块的入口文件。

rule.js,模块index.js使用的,做为WAF的规则记录文章:

//Rules are from ShareWAF(sharewaf.com)
//You can edit the rules.
exports.regexp_waf_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
];

规则是可以编辑的,使用者可以自己修改。

还有一个测试文件:

var express = require('express');
var app = express();
var express_waf_middleware = require("./index");

var waf_options = {
    url: 1, //detect the url
    userAgent: 1,   //detect the user-agent
    cookies: 1, //detect the cookies
    body: 1,    //detect the body
    log: 0  //print log informaton
}
app.use(express_waf_middleware(waf_options));

app.get('/', function (req, res) {
    res.send('Hello world');
});

app.listen(8000);
console.log("Test server at port:8000");
console.log("You can use these urls for testing:")
console.log("http://127.0.0.1:8000/");
console.log("http://127.0.0.1:8000/add.asp?id=1' or select * from admin");
console.log("http://127.0.0.1:8000/<script>alert('hello');</script>")

此文件用于测试模块功能的正确性。

再则是package.json,此文件由:

npm init

创建:

{
  "name": "express-waf-middleware",
  "version": "0.0.3",
  "description": "a WAF(web application firewall) for the Express.",
  "main": "index.js",
  "scripts": {
    "test": "node test"
  },
  "keywords": [
    "express",
    "waf"
  ],
  "author": "WangLiwen<wangliwen@sharewaf.com>(http://www.sharewaf.com)",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.1"
  }
}

最后,是readme.md,用于介绍模块,会显示在npm网站页面上,当然是在提交之后。

## express-waf-middleware
a WAF(web application firewall) for the Express.

## Installation
```bash
$ npm install express-waf-middleware
```
## usage
```js
var waf_options = {
    url: 1, //detect the url
    userAgent: 1,   //detect the user-agent
    cookies: 1, //detect the cookies
    body: 1,    //detect the body
    log: 0  //print log informaton
}
app.use(express_waf_middleware(waf_options));
```

## example
```js
var express = require('express');
var app = express();
var express_waf_middleware = require("./index");

var waf_options = {
    url: 1, //detect the url
    userAgent: 1,   //detect the user-agent
    cookies: 1, //detect the cookies
    body: 1,    //detect the body
    log: 0  //print log informaton
}
app.use(express_waf_middleware(waf_options));

app.get('/', function (req, res) {
    res.send('Hello world');
});

app.listen(8000);
console.log("Test server at port:8000");
console.log("You can use these urls for testing:")
console.log("http://127.0.0.1:8000/");
console.log("http://127.0.0.1:8000/add.asp?id=1' or select * from admin");
console.log("http://127.0.0.1:8000/<script>alert('hello');</script>")
app.listen(3000)
```

提交模块到NPM

首先在npm官网注册帐号。

注意:注册后需要到邮件中激活,否则不能提交项目。

开始提交:

先要登录,

npm login

使用上面注册的帐号密码。

再使用项目提交指令:

npm publish

很快便提交成功。

来到npm官网,搜索:express-waf-middleware

确认提交成功。

再在项目中使用试试:

var express = require('express');
var app = express();
var express_waf_middleware = require("express-waf-middleware");

var waf_options = {
    url: 1, //detect the url
    userAgent: 1,   //detect the user-agent
    cookies: 1, //detect the cookies
    body: 1,    //detect the body
    log: 0  //print log informaton
}
app.use(express_waf_middleware(waf_options));

app.get('/', function (req, res) {
    res.send('Hello world');
});

app.listen(8000);
console.log("Test server at port:8000");
console.log("You can use these urls for testing:")
console.log("http://127.0.0.1:8000/");
console.log("http://127.0.0.1:8000/add.asp?id=1' or select * from admin");
console.log("http://127.0.0.1:8000/<script>alert('hello');</script>")