关于如何防止NOSQL注入Node.js Express Server的想法
#安全 #node #nosql #mongodb

NOSQL注入是一种脆弱性,攻击者能够将任意文本注入NOSQL查询。

NOSQL注射与传统的SQL注入攻击非常相似,只是攻击是针对NOSQL数据库的攻击。<​​/em> nosql是任何不使用SQL的数据库的一般术语使用NOSQL的系统(DBMS)是mongodb。

NoSQL injection diagram

在这篇文章中,我想描述以下内容以显示如何防止NoSQL注入:

  1. 构建一个简单的nodejs应用
  2. 了解NOSQL注射攻击是什么
  3. 使用npm软件包来防止攻击

对于先决条件,让我们假设我们有一个现成的蒙古群集群或本地蒙古德安装,并且具有连接URI,例如。 http://localhost:27017

项目设置

让我们初始化node.js应用并安装几个软件包。在空文件夹中运行以下命令。

$ npm init -y
$ npm i express mongoose 
$ npm i nodemon dotenv -D

或,使用Yarn代替。

$ npm init -y
$ yarn add express mongoose 
$ yarn add nodemon dotenv –-dev

创建app.jsmodels/user.model.js

app.js

require('dotenv').config();

const express = require('express');
const mongoose = require('mongoose');

const routes = require('./routes/index');

const app = express();

app.use(express.json());

app.use(routes);

mongoose
  .connect(process.env.MONGODB_URI)
  .then(() => {
    console.log('Mongoose connected 🍃');
    app.listen(3000, () => {
      console.log('Server is up and running 🚀');
    });
  })
  .catch((error) => {
    console.log(error);
  });

型号/user.model.js

const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
  username: {
    type: String,
    unique: true
  },
  password: {
    type: String,
    unique: true
  }
});

const User = mongoose.model('User', userSchema);

module.exports = User;

随着设置的范围,让我们首先查看简单的NOSQL攻击。
出于演示目的,我将创建一个简单的路由文件。

路线/索引

const express = require('express');

const User = require('../models/user.model');

const router = express.Router();

router.get('/users', async (req, res, next) => {
  return res.json({
    users: await User.find({}).exec()
  });
});

router.post('/login', async (req, res, next) => {
  const { username, password } = req.body;

  const user = await User.findOne({ username, password }).exec();

  res.json({
    message: `Logged in as ${user.username}`
  });
});

module.exports = router;

是时候向/users提出请求以查看我们拥有的东西了。如前所述,我们将使用 Postman

// GET localhost:3000/users

{
    "users": [
        {
            "_id": "6125401c491c0b0bfd123165",
            "username": "test1",
            "password": "123456",
            "__v": 0
        },
        {
            "_id": "6125401c491c0b0bfd123166",
            "username": "test2",
            "password": "abcdef",
            "__v": 0
        },
        {
            "_id": "6125401c491c0b0bfd123167",
            "username": "test3",
            "password": "sdjndsn",
            "__v": 0
        }
    ]
}

这是服务器返回的响应。从上面的代码块中可以看出,我们有三个用户(例如用于演示目的)。

接下来,尝试使用其中一个凭证登录。在下面的请求正文中向/login提出帖子请求。

{
  "username": "test1",
  "password": "123456"
}

我们会得到以下回应。到目前为止,一切似乎都很正常,所以让我们更深入地深入研究!

// POST localhost:3000/login

{
    "message": "Logged in as test1"
}

执行演示NOSQL注入!!!

NoSQL Injection

要执行NOSQL注入攻击,只需将体内的密码值从"123456"更改为{ "$ne": "null" }。因此,新请求主体看起来如下:

{
  "username": "test1",
  "password": { "$ne": null }
}

请抓住!
$ne操作员做什么?让我解释一下。

$ne操作员告诉Mongo检查不等于。也就是说,MongoDB不要检查密码是否正确的值,而是简单地检查密码字段是否为null。由于在任何情况下都不能无效密码字段,因此我们可以在不知道密码的情况下欺骗MongoDB。

使用新修改的请求主体向/login提出后请求后,我们将从服务器中获得以下响应。

// POST localhost:3000/login

{
    "message": "Logged in as test1"
}

哦,天哪!ð±

有不止一种做同一件事的方法。例如,我们本可以使用{ "$gt": "" }而不是$ne运算符。

幸运的是,防止这种攻击与执行它一样容易。接下来,让我们看一下如何防止NOSQL注入攻击。

介绍NPM模块

我们将从NPM安装express-mongo-sanitize软件包。运行以下命令:

$ npm i express-mongo-sanitize

或,

$ yarn add express-mongo-sanitize

我们可以在此处学习有关此模块的详细信息:
https://www.npmjs.com/package/express-mongo-sanitize

要求包装返回中间件功能,然后可以按照下面的示例使用。

// Prevent NoSQL injection
const mongoSanitize = require('express-mongo-sanitize');

...

// Prevent NoSQL injection
app.use(
  mongoSanitize({
    onSanitize: ({ req, key }) => {
      // Throw an error
      // Catch with express error handler
    }
  })
);

我希望这篇文章有助于防止NOSQL注入攻击时进行Node.js Express Server。

有关完整的源代码,请参阅此github repo:
https://github.com/liyang51827/express-nosql-injection-demo