Felps03/NoSQL-Injection

GitHub: Felps03/NoSQL-Injection

一个教育性质的 NoSQL 注入 POC 项目,通过脆弱与安全两条登录路由的对比演示攻击原理及 Zod 校验防护方案。

Stars: 1 | Forks: 0

# NoSQL Injection POC [![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/ad/ad5834178f7599af9fdda11629d49cae07f2997beec49821b2920eff5bfd50e7.svg)](https://github.com/Felps03/NoSQL-Injection/actions/workflows/ci.yml) [![Coverage](https://img.shields.io/badge/coverage-92%25-brightgreen.svg)](#运行测试) [![License: MIT](https://img.shields.io/badge/license-MIT-yellow.svg)](./LICENSE) [![Node.js](https://img.shields.io/badge/node-24.x-green.svg)](https://nodejs.org) 两个完全相同的登录路由。向它们发送相同的恶意 payload:一个让你无需密码即可登录,另一个则通过 `400 Bad Request` 将你拦截。这就是曾经导致各地生产系统崩溃的同一种漏洞——现在它在本地运行,完全由你掌控,准备好供你研究、破解并真正理解它。 ## ✨ 亮点 - 🎯 **真实攻击,现场演示** — 同样的路由,同样的 payload:一个无需密码即可认证,另一个则进行拦截。 - ⚡ **现代技术栈** — Node 24, Express 5, Mongoose 8, 100% ESM,零 Babel。 - 🛡️ **真正的缓解措施** — 使用 [Zod](https://zod.dev/) 进行 schema 验证,而不是博客里那种通用的“清理”。 - 🧪 **真正的测试** — 使用 `mongodb-memory-server` 进行集成测试,覆盖率超过 90%。 - 🐳 **一键启动** — `docker compose up --build`,API 即刻上线并连接到 MongoDB。 - 📄 **深度文档** — 包含 OpenAPI、Postman collection 以及逐步展示攻击流程的 Mermaid 图表。 ## 目录 - [亮点](#-destaques) - [关于项目](#sobre-o-projeto) - [安全警告](#-aviso-de-segurança) - [技术栈](#-stack) - [环境要求](#requisitos) - [本地安装](#instalação-local) - [环境变量](#variáveis-de-ambiente) - [本地运行](#-rodando-localmente) - [使用 Docker 运行](#-rodando-com-docker) - [运行测试](#-rodando-os-testes) - [可用脚本](#scripts-disponíveis) - [API 路由](#rotas-da-api) - [示例:创建用户](#exemplo-criar-usuário) - [示例:易受攻击的登录](#-exemplo-login-vulnerável) - [示例:安全的登录](#-exemplo-login-seguro) - [图表:易受攻击 vs. 安全](#-diagrama-vulnerável-vs-seguro) - [如何防止 NoSQL Injection](#-como-prevenir-nosql-injection) - [现代化决策](#-decisões-de-modernização) - [文件夹结构](#-estrutura-de-pastas) - [CI](#-ci) - [后续计划](#-próximos-passos) ## 关于项目 本项目是一个教育性质的概念验证 (POC),以实践方式演示了在使用 MongoDB 的 Node.js API 中 NoSQL Injection 是如何发生的——以及正确的输入验证(使用 [Zod](https://zod.dev/))如何化解同类攻击。 该 API 暴露了两个等效的登录路由:一个故意设计为易受攻击,另一个则是安全的,以便进行并排对比。这不是一篇关于安全的纯理论文章——而是运行中、被利用、被修复的漏洞,包含你可以几分钟内克隆并测试的真实代码。 ## ⚠️ 安全警告 本项目**仅用于学习和防御意识提升目的**,应在本地/受控环境(你的机器、隔离的 Docker container)中运行。它不应被公开暴露、用于攻击第三方系统,也不应被视为攻击工具。目的是理解漏洞从而知道如何预防它,而不是在这个学习环境之外利用它。 ## 🧰 技术栈 - Node.js 24 - Express 5 - MongoDB - Mongoose 8 - Zod - Jest - Supertest - mongodb-memory-server - Docker - Docker Compose ## 环境要求 - Node.js 24+ - npm - Docker 和 Docker Compose(如果打算通过 container 运行) ## 本地安装 ``` npm install ``` ## 环境变量 `.env.example` 文件记录了应用使用的变量: ``` NODE_ENV=development PORT=3333 MONGO_URL=mongodb://localhost:27017/nosql-injection ``` - `NODE_ENV`:控制运行模式(在 `development` 模式下,未处理的错误会在响应正文中返回 stack trace)。 - `PORT`:服务器监听的 HTTP 端口。 - `MONGO_URL`:MongoDB 的连接字符串。这是必填项——如果未设置,应用启动时会失败。 将该文件复制为 `.env` 并根据需要进行调整: ``` cp .env.example .env ``` ## 🚀 本地运行 确保在 `localhost:27017` 有可用的 MongoDB: ``` MONGO_URL=mongodb://localhost:27017/nosql-injection npm run dev ``` 或者,使用已配置好的 `.env` 文件: ``` npm run dev ``` ## 🐳 使用 Docker 运行 ``` docker compose up --build ``` 这会同时启动 API 和 MongoDB,并且它们已经互联。要验证 API 是否已上线: ``` curl http://localhost:3333/health ``` 停止运行: ``` docker compose down ``` ## 🧪 运行测试 ``` npm test ``` 集成测试使用了 [mongodb-memory-server](https://github.com/typegoose/mongodb-memory-server),它会自动启动一个内存中的 MongoDB。无需运行真实的 MongoDB 即可进行测试。 `npm test` 还会在终端(以及 `__tests__/coverage` 中)生成覆盖率报告。README 顶部的覆盖率徽章是最后一次数据的截取——如果覆盖率发生显著变化,请记得更新它。 ## 可用脚本 - `npm start` — 以生产模式启动应用。 - `npm run dev` — 启动应用并实现自动重载 (`node --watch`)。 - `npm test` — 运行测试套件 (Jest + Supertest)。 - `npm run lint` — 使用 ESLint 检查代码。 - `npm run lint:fix` — 自动修复可以修复的问题。 - `npm run format` — 使用 Prettier 格式化代码。 - `npm run format:check` — 检查格式而不修改文件。 ## API 路由 | 方法 | 路由 | 描述 | | ------ | ------------------------ | ------------------------------------------- | | GET | `/health` | 检查 API 是否在线 | | GET | `/users` | 列出已注册的用户 | | POST | `/users` | 创建用户 | | POST | `/auth/vulnerable/login` | 易受 NoSQL Injection 攻击的登录 | | POST | `/auth/safe/login` | 受 Zod 验证保护的登录 | ## 示例:创建用户 ``` curl -X POST http://localhost:3333/users \ -H "Content-Type: application/json" \ -d '{"email":"teste@example.com","password":"123456"}' ``` ## 🔓 示例:易受攻击的登录 使用正确密码的常规登录: ``` curl -X POST http://localhost:3333/auth/vulnerable/login \ -H "Content-Type: application/json" \ -d '{"email":"teste@example.com","password":"123456"}' ``` NoSQL Injection 的教育性 payload —— 它不发送密码,而是发送一个 MongoDB 运算符 (`$gt`,即“大于空字符串”),该条件始终为真: ``` curl -X POST http://localhost:3333/auth/vulnerable/login \ -H "Content-Type: application/json" \ -d '{"email":"teste@example.com","password":{"$gt":""}}' ``` 该路由在不知道真实密码的情况下对用户进行了认证。发生这种情况是因为 `req.body` 被直接传递给了 Mongoose 的查询 (`User.findOne({ email, password })`),而没有验证 `password` 字段的类型。**故意**将该路由设计为易受攻击的,以作演示之用。 ## 🔒 示例:安全的登录 使用正确密码的常规登录: ``` curl -X POST http://localhost:3333/auth/safe/login \ -H "Content-Type: application/json" \ -d '{"email":"teste@example.com","password":"123456"}' ``` 相同的注入 payload,现在已被拦截: ``` curl -X POST http://localhost:3333/auth/safe/login \ -H "Content-Type: application/json" \ -d '{"email":"teste@example.com","password":{"$gt":""}}' ``` 在这里,Zod 在对数据库进行任何查询之前就会验证请求体,要求 `password` 必须是一个 `string`。像 `{"$gt": ""}` 这样的对象无法通过验证,API 会响应 `400 Bad Request`,根本不会去 MongoDB 中执行查询。 ## 🧭 图表:易受攻击 vs. 安全 下面的图表对比了相同的攻击 payload (`password: { "$gt": "" }`) 经过两条路由的过程: ``` sequenceDiagram participant Cliente participant Vulneravel as /auth/vulnerable/login participant Segura as /auth/safe/login participant Zod participant MongoDB Note over Cliente: Payload malicioso
password: { "$gt": "" } rect rgb(255, 230, 230) Cliente->>Vulneravel: POST { email, password: {"$gt": ""} } Vulneravel->>MongoDB: findOne({ email, password: {"$gt": ""} }) Note right of MongoDB: "$gt": "" é sempre verdadeiro,
então qualquer senha "passa" MongoDB-->>Vulneravel: usuário encontrado Vulneravel-->>Cliente: 200 OK (autenticado sem senha real) end rect rgb(230, 255, 230) Cliente->>Segura: POST { email, password: {"$gt": ""} } Segura->>Zod: valida schema (password precisa ser string) Zod-->>Segura: falha na validação Segura-->>Cliente: 400 Bad Request (payload rejeitado) Note over MongoDB: Query nunca chega a ser executada end ``` Zod 在查询之前引入的决策流程图: ``` flowchart TD A[Requisição chega em /auth/safe/login] --> B{password é string?} B -- Não, é objeto/operador Mongo --> C[400 Bad Request
Invalid request payload] B -- Sim --> D[User.findOne com email e password] D --> E{Encontrou usuário?} E -- Sim --> F[200 OK] E -- Não --> G[400 Bad Request
user/pass not found] ``` ## 🛡️ 如何防止 NoSQL Injection - 在使用前验证所有用户输入。 - 在期望原始类型(string, number 等)的地方拒绝对象。 - 在应用边界处使用 schema 验证(Zod, Joi 等)。 - 在将 payload 传递给查询之前对其进行清理。 - 切勿将 `req.body` 直接传递给数据库查询。 - 切勿信任来自客户端的数据。 - 在真实项目中,使用真正的身份验证(token, session, OAuth 等)。 - 在真实项目中,始终对密码进行哈希处理(bcrypt, argon2 等)—— 切勿以明文形式存储。 ## 🔧 现代化决策 - Node 10 → Node 24。 - 移除 Babel —— 项目运行原生 ESM,无需转译。 - 移除 Cluster。 - Express 4 → Express 5。 - Mongoose 5 → Mongoose 8。 - 移除 Sequelize 和 PostgreSQL —— 项目仅通过 Mongoose 使用 MongoDB。 - 移除 Webpack。 - 移除旧的 Husky 配置。 - 将 Jest 和 Supertest 更新到最新版本。 - 为健康检查、用户和身份验证路由添加了集成测试。 - 更新 Dockerfile 以支持 Node 24 并实现无 Babel 构建。 - 添加了 Docker Compose,内置 MongoDB 服务。 - 重写 README 以反映项目的当前状态。 - 通过 GitHub Actions 添加了 CI(在每次 push/PR 时执行 lint、格式检查和测试)。 ## 📁 文件夹结构 ``` . ├── .github │ └── workflows │ └── ci.yml # Pipeline de CI (lint, format check e testes) ├── src │ ├── app │ │ ├── controllers # Regras de cada rota (Health, Users, Auth) │ │ └── schemas # Schemas do Mongoose (dados) e do Zod (validação) │ ├── database # Conexão com o MongoDB │ ├── helpers # Logger e enums (códigos HTTP) │ ├── routes # Definição das rotas por domínio │ ├── app.js # Configuração do Express │ └── server.js # Ponto de entrada da aplicação ├── __tests__ │ ├── integration # Testes de integração (Supertest) │ └── support # Setup do mongodb-memory-server ├── swagger │ └── openapi.yaml # Documentação OpenAPI da API ├── postman │ └── NoSQL Injection.postman_collection.json ├── Dockerfile ├── docker-compose.yml └── .env.example ``` ## ⚙️ CI 位于 `.github/workflows/ci.yml` 的 workflow 会在每次向 `master` 推送以及 pull request 时运行,执行以下操作: 1. `npm ci` 2. `npm run lint` 3. `npm run format:check` 4. `npm test` ## 🗺️ 后续计划 本 POC 范围之外的演进建议: - 添加 bcrypt 以对密码进行哈希处理。 - 添加真实的身份验证(JWT, session 等)。 - 在登录路由上添加 rate limit。 - 改进错误处理(针对不同类型的失败提供更具体的响应)。 - 发布 Swagger 的 HTML 文档。 - 提高 controller 中错误处理块 (`catch`) 的测试覆盖率。 由 [Felps03](https://github.com/Felps03) 制作。如果这个项目帮助你理解了 NoSQL Injection,请在仓库中点个 ⭐。
标签:CISA项目, GNU通用公共许可证, Maven, MITM代理, MongoDB, Node.js, Web安全, Zod, 安全防护, 漏洞验证, 版权保护, 自定义脚本, 蓝队分析, 请求拦截