NoSQL注入漏洞与防护(进阶篇)
字数 1170 2025-11-26 01:30:18
NoSQL注入漏洞与防护(进阶篇)
1. 漏洞描述
NoSQL注入是一种针对非关系型数据库(如MongoDB、Cassandra、Redis等)的注入攻击。与传统SQL注入不同,NoSQL注入利用的是应用程序对用户输入的不安全处理,通过操纵查询语法(如JSON、BSON)或运算符(如$ne, $gt)来绕过认证、泄露数据或篡改数据库。常见场景包括登录绕过、数据提取或任意命令执行。
2. 漏洞原理与攻击方式
关键问题:应用程序未对用户输入进行过滤或类型检查,直接将用户输入拼接到NoSQL查询中。
示例场景(以MongoDB为例):
假设登录查询代码如下(Node.js + MongoDB):
db.users.findOne({
username: req.body.username,
password: req.body.password
});
攻击者可通过以下方式绕过登录:
-
运算符注入:
- 输入
username=admin&password[$ne]=123,查询被解析为:{ "username": "admin", "password": { "$ne": "123" } } - 含义:查询
password字段不等于"123"的记录,若admin用户存在,则返回该用户记录,实现登录绕过。
- 输入
-
正则表达式注入:
- 输入
username[$regex]=.*&password[$ne]=,匹配任意用户名并绕过密码检查。
- 输入
-
逻辑操作符滥用:
- 使用
$where子句执行JavaScript代码(若开启):
攻击者可通过输入{ "$where": "this.password === '"+userInput+"'" }' || 1==1 //注入代码。
- 使用
3. 攻击演示(循序渐进)
步骤1:识别注入点
- 检测输入点:登录表单、API参数、过滤条件等。
- 尝试输入特殊字符(如
'、{、$)观察错误回显或行为异常。
步骤2:构造Payload
- 绕过认证:
POST /login HTTP/1.1 Content-Type: application/json { "username": "admin", "password": { "$ne": "invalid" } } - 提取数据:
利用$regex逐字符判断密码:{ "password": { "$regex": "^a" } } // 测试密码首字母是否为a
步骤3:自动化利用
- 工具:NoSQLMap、Burp Suite扩展(如
NoSQLi插件)。 - 脚本示例(Python):
import requests payload = {"username": "admin", "password": {"$ne": ""}} response = requests.post("http://target/login", json=payload) if "Welcome" in response.text: print("登录绕过成功!")
4. 防护方案
4.1 输入验证与过滤
-
严格类型检查:确保输入为预期类型(如字符串而非对象)。
// 错误:直接使用req.body // 正确:强制转换类型 const username = String(req.body.username); const password = String(req.body.password); -
黑名单过滤:禁止查询中包含运算符(如
$、__)。 -
白名单验证:仅允许特定字符(如字母数字)。
4.2 参数化查询
- 使用ORM(如Mongoose)的安全方法:
// 错误:拼接查询 db.users.findOne({ username: userInput }); // 正确:使用ORM封装 UserModel.findOne({ username: userInput }); // ORM自动转义
4.3 最小权限原则
- 数据库用户仅赋予必要权限(禁止
dbAdmin角色用于应用查询)。
4.4 启用安全配置
- MongoDB禁用服务器端JavaScript执行(
noscripting模式)。 - 使用网络隔离限制数据库直接暴露。
4.5 日志与监控
- 记录异常查询(如包含运算符的请求)。
- 部署WAF规则检测NoSQL注入模式。
5. 总结
NoSQL注入通过滥用查询语法绕过防护,核心在于输入验证缺失和类型混淆。防护需结合白名单验证、参数化查询和最小权限原则,同时针对不同数据库(如MongoDB、Cassandra)调整策略。