Web安全
基础漏洞
01前端基础【HTML】
02前端基础【CSS】
03后端基础【PHP速通】
04后端基础【PHP面向对象】
05MySQL基础操作
06前后端联动【代码练习】
07SQL注入【1】
07SQL 注入【2】
08SQL注入 Labs
08SQL注入速查表
09XSS
09跨站脚本攻击【XSS】
09XSS Labs
10跨站请求伪造【CSRF】
11服务器端请求伪造【SSRF】
12XML 外部实体注入【XXE】
13代码执行漏洞
14命令执行漏洞
15文件包含漏洞
16文件上传漏洞
17反序列化漏洞
18业务逻辑漏洞
19未授权访问漏洞集合
20跨源资源共享【CORS】
21SSTI模板注入
22并发漏洞
23点击劫持【Clickjacking 】
24请求走私
25路径遍历
26访问控制
27身份验证漏洞
28WebSocket
29Web缓存中毒
30HTTP 主机头攻击
31信息泄露漏洞
32原型污染
33NoSQL注入
API 安全
01web应用程序
02HTTP协议
03API概述
04分类类型
05交换格式
06身份验证
07常见API漏洞
08crAPI靶场
09JWT
10OAuth 2.0身份验证
11GraphQL【1】
11GraphQL【2】
12DVGA靶场
13服务器端参数污染
14API文档
15API Labs
16OAuth Labs
17GraphQL API Labs
18JWT Labs
小程序
小程序抓包
数据库
MySQL
Oracle
MongoDB
Redis
PostgreSQL
SQL server
中间件
Nginx
Apache HTTP Server
IIS
Tomcat
框架
ThinkPHP
Spring
Spring Boot
Django
访问控制
-
+
首页
33NoSQL注入
NoSQL 数据库以不同于传统 SQL 关系表的格式存储和检索数据。它们使用多种查询语言,而非像 SQL 这样的通用标准,并且关系约束更少。 NoSQL(非关系型数据库)并不是单一的数据库系统,而是一类**数据模型灵活、不依赖固定表结构**的数据库的统称。 由于其数据模型(文档、键值、列族、图等)差异极大,**没有统一的 “语法”**,不同类型的 NoSQL 数据库查询和操作语法截然不同。 ## 概述 **NoSQL 注入**是针对非关系型数据库(NoSQL)的注入攻击,其原理与传统 SQL 注入类似 —— 攻击者通过控制用户输入,篡改数据库查询逻辑,以未授权方式访问、修改或泄露数据。 与 SQL 注入不同的是,NoSQL 数据库不使用结构化查询语言(SQL),而是采用 JSON、键值对、文档等格式的查询语法,因此注入方式和利用场景有显著差异。 ## NoSQL 数据库 NoSQL 数据库(如 MongoDB、Redis、Cassandra、CouchDB 等)旨在应对大规模数据存储和高并发场景,其核心特点包括: - 不依赖固定表结构(无 schema),查询语法灵活(如 MongoDB 使用类似 JSON 的查询文档); - 支持多种数据模型(文档型、键值型、列族型等); - 通常通过 API 或驱动直接接收客户端构造的查询对象。 **注入根源**:当应用程序直接将用户输入拼接或嵌入到 NoSQL 查询中,而未进行严格过滤时,攻击者可构造特殊输入篡改查询逻辑(如插入数据库操作符、修改查询条件等),实现注入攻击。 ## 示例 不同 NoSQL 数据库的查询语法不同,注入方式也有差异,以最常用的**MongoDB**(文档型数据库)和**Redis**(键值型数据库)为例说明。 ### MongoDB 注入 MongoDB 使用类似 JSON 的**BSON(Binary JSON)** 格式作为查询语言,支持丰富的查询操作符(如`$eq`、`$ne`、`$gt`、`$or`等)。若用户输入直接作为查询条件的键或值,可能被注入恶意操作符。 **典型场景:认证绕过**,假设应用程序的登录逻辑使用以下代码验证用户(Node.js + MongoDB): ```javascript // 不安全的查询:直接将用户输入作为查询条件 const username = req.body.username; const password = req.body.password; // 风险:若用户输入被控制,可注入查询操作符 db.collection('users').findOne({ username: username, password: password }, (err, user) => { if (user) { /* 登录成功 */ } }); ``` 攻击者可构造如下输入绕过验证: - **用户名**:`admin`(目标用户) - **密码**:`{"$ne": ""}`(`$ne`表示 “不等于”,此条件恒为真) 此时查询被篡改为: ```javascript { username: "admin", password: { $ne: "" } } ``` 该查询会匹配`username`为`admin`且`password`不为空的所有用户(无需知道真实密码),直接登录成功。 **其他注入场景**: - 数据泄露:通过`$where`操作符注入 JavaScript 代码(MongoDB 支持在查询中执行 JS) ```javascript // 恶意输入:username=admin&password[$where]=1==1 // 篡改后的查询会执行1==1(恒真),返回所有admin用户数据 { username: "admin", password: { $where: "1==1" } } ``` - 批量操作篡改:注入`$set`等更新操作符,修改其他用户数据。 ```javascript // 假设应用允许用户更新个人信息,输入直接作为更新条件 // 恶意输入:id=123&data[$set][role]=admin // 篡改后的更新操作会将id=123的用户角色改为admin db.users.updateOne({ _id: "123" }, { $set: { role: "admin" } }) ``` ### Redis 注入 Redis 是键值型数据库,通过命令行式的协议(如`SET key value`、`GET key`)操作数据。若应用直接将用户输入拼接为 Redis 命令,可能导致注入。 **典型场景:命令注入**,假设应用使用用户输入作为 Redis 键名查询数据(Python 示例): ```python # 不安全的代码:直接拼接用户输入为Redis命令 user_input = request.args.get('key') # 风险:用户输入可包含分号分隔的额外命令 command = f"GET {user_input}" result = redis_client.execute_command(command) ``` 攻击者可构造输入:`user_key; SET admin true`,此时拼接后的命令为: ```txt GET user_key; SET admin true ``` Redis 会执行两条命令:先查询`user_key`,再将`admin`设为`true`,实现未授权数据修改。 更危险的是,若 Redis 配置允许(如开启`config set dir`和`dbfilename`),攻击者可注入命令写入 webshell: ```txt user_key; config set dir /var/www/html; config set dbfilename shell.php; set x "<?php eval($_POST['cmd']);?>"; save ``` 该命令会在 web 目录下生成包含恶意代码的`shell.php`,实现远程代码执行(RCE)。 ## 危害 **未授权访问**:绕过登录验证,直接获取管理员权限; **数据泄露**:窃取敏感数据(如用户信息、支付记录); **数据篡改**:修改数据库内容(如篡改订单金额、提升用户权限); **服务器控制**:结合 Redis 等数据库的特性,可能执行系统命令、写入 webshell,完全控制服务器。 ## 防御措施 NoSQL 注入的防御核心是**严格校验用户输入**,**避免直接拼接输入到查询中**,结合数据库特性采取针对性措施。 **1. 输入验证与过滤** 对用户输入进行类型检查(如数字、字符串)和长度限制; 过滤 NoSQL 特有的关键字 / 操作符(如 MongoDB 的`$ne`、`$where`、`$set`;Redis 的分号`;`、`config`、`set`等); 示例(过滤 MongoDB 操作符): ```javascript function sanitizeInput(input) { if (typeof input === 'object') { // 递归过滤对象中的操作符键 for (const key in input) { if (key.startsWith('$')) { delete input[key]; // 删除包含$的键(操作符) } else { sanitizeInput(input[key]); } } } return input; } ``` **2. 使用参数化查询(绑定变量)** NoSQL 数据库的驱动通常支持参数化查询,将用户输入作为 “值” 而非 “查询逻辑” 传入,避免注入。 **MongoDB 示例(安全写法)**: ```javascript // 使用参数化查询,用户输入仅作为值传递 db.collection('users').findOne({ username: req.body.username, // 输入仅作为值,不会被解析为操作符 password: req.body.password }); ``` **Redis 示例(安全写法)**: ```python # 使用驱动提供的方法,避免直接拼接命令 user_input = request.args.get('key') # 安全:将输入作为参数传递,而非拼接命令 result = redis_client.get(user_input) ``` **3. 最小权限原则** 限制数据库账户权限:MongoDB 账户仅授予必要的`find`、`update`权限,禁止`$where`等危险操作;Redis 账户禁用`config`、`save`等敏感命令; 禁止数据库直接暴露在公网,通过应用服务器中转访问。 **4. 使用 ORM/ODM 工具** 通过对象关系映射(ORM)或对象文档映射(ODM)工具(如 MongoDB 的 Mongoose)操作数据库,这些工具通常内置输入过滤和参数化查询机制,减少注入风险。 ```javascript // Mongoose示例:通过Schema定义限制输入格式 const userSchema = new mongoose.Schema({ username: { type: String, required: true }, password: { type: String, required: true } }); const User = mongoose.model('User', userSchema); // 安全查询:Mongoose会自动处理输入,避免注入 User.findOne({ username: req.body.username, password: req.body.password }); ``` **5. 限制返回数据** 避免使用`find()`返回所有字段,通过`projection`指定允许返回的字段(如排除`password`、`creditCard`等敏感信息); MongoDB 示例: ```javascript // 仅返回username和email字段,不返回password db.users.findOne({ username: "admin" }, { username: 1, email: 1, _id: 0 }); ``` **6. 定期审计与更新** 审计数据库日志,监测异常查询(如包含`$where`、`config`的命令); 及时更新数据库和驱动版本,修复已知的注入漏洞(如 MongoDB 旧版本的`$where`沙箱绕过)。
毛林
2025年9月10日 18:22
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文档(打印)
分享
链接
类型
密码
更新密码