angular层无法防护sql注入,防御必须落在nestjs数据库操作环节;唯一可靠方式是驱动层参数化查询(如mysql2用?、pg用$1),严禁字符串拼接,表名列名等结构部分须白名单校验。

Angular 层对 SQL 注入完全无防护能力,所有防御必须落在 NestJS 的数据库操作环节;只要有一处 query、execute 或 ORM 原生 SQL 调用拼接了用户输入,整个链路就已失守。
Node.js 驱动层必须用参数化查询,不能拼接字符串
mysql2、pg、sqlite3 等驱动原生支持参数化,这是唯一可依赖的机制。NestJS 本身不干涉数据库交互方式,安全与否取决于你如何调用底层 client 或 queryRunner。
-
db.execute('SELECT * FROM users WHERE email = ? AND status = ?', [req.query.email, 'active'])✅ 安全,由驱动完成类型绑定与上下文隔离 -
db.query(`SELECT * FROM users WHERE id = ${req.params.id}`)❌ 危险,模板字符串插值 = 字符串拼接 = 可注入 -
db.query('SELECT * FROM users WHERE name = ' + mysql.escape(req.body.name))❌ escape 仅适配 MySQL,且在宽字节、反引号、十六进制编码等场景下可被绕过 - PostgreSQL 用户注意:
$1、$2是位置占位符,不是变量插值,client.query('WHERE id = $1', [id])才对;`WHERE id = ${id}`仍是拼接
NestJS 中 ORM 原生 SQL 接口是高危区,需逐行审计
Prisma、TypeORM、Sequelize 在默认 find 方法中启用参数化,但它们都暴露了绕过防护的“后门”:原生 SQL 执行接口。这些接口一旦传入拼接字符串,ORM 的安全假设即刻崩塌。
详细的 Three.js 3D 图形参考,涵盖场景设置、相机、几何体、材质、光照、动画、控制器、加载器、数学工具和调试。
-
prisma.$queryRaw`SELECT * FROM users WHERE email = ${req.query.email}`❌ 模板字符串插值不是参数化,${...}在 JS 层就已完成字符串拼接 -
prisma.$queryRaw`SELECT * FROM users WHERE email = ${prisma.escape(req.query.email)}`❌ escape 不等于参数化,且 Prisma 的 escape 并非为防注入设计 -
typeOrm.query('UPDATE logs SET note = ? WHERE id = ?', [note, id])✅ 安全,? 占位符 + 参数数组 -
sequelize.query(`DELETE FROM sessions WHERE token = '${req.headers.authorization}'`)❌ 即使加了sequelize.escape(),也不推荐——它无法覆盖所有编码边界
动态表名、字段名、ORDER BY 必须走硬编码白名单
参数化只保护「值」,不保护 SQL 结构。任何把用户输入直接用于 FROM、SELECT 列、ORDER BY、GROUP BY 的行为,都是在开放注入入口。
- 错误做法:
const sql = `SELECT * FROM ${req.query.table} WHERE id = ?` - 正确做法:
const allowedTables = { users: 'users', posts: 'posts', comments: 'comments' }; const table = allowedTables[req.query.table] || 'users'; const sql = `SELECT * FROM ${table} WHERE id = ?` - 排序字段同理:
const validSorts = { name: 'name', email: 'email', createdAt: 'created_at' }; const sort = validSorts[req.query.sort] || 'id'; const order = req.query.order === 'desc' ? 'DESC' : 'ASC'; const sql = `SELECT * FROM users ORDER BY ${sort} ${order}` - 别信正则过滤:
req.query.sort.replace(/[^a-zA-Z_]/g, '')无法阻挡name%00, (SELECT ...)或反引号包裹的标识符
所有用户输入源都必须纳入校验,不只是 req.body
开发者常只检查 body,却忽略 query、params、headers 甚至 IP 地址——只要这些数据进了 SQL,就必须走参数化或白名单流程。
-
req.query.page和req.query.limit用于分页?→ 必须转成整数后作为参数传入:db.execute('SELECT * FROM items LIMIT ?, ?', [offset, limit]) -
req.headers['x-tenant-id']用于多租户?→ 不能直接拼进WHERE tenant_id = '${tenantId}',应先白名单校验(如匹配 UUID 格式),再作为参数传入 -
req.params.slug查文章?→db.execute('SELECT * FROM posts WHERE slug = ?', [req.params.slug]),而非字符串拼接 -
parseInt(req.query.id)只是类型转换,不是安全动作;若后续仍拼进 SQL 字符串,照样危险
最易被忽略的一点:NestJS 的拦截器(Interceptor)和管道(Pipe)只能做前置校验,不能替代参数化。它们拦不住 curl 直接发来的恶意 query,也改不了你写错的那一行 query(`...${req.query.xxx}...`)。防御的成败,只系于那一行 SQL 构造是否把用户输入当“值”而非“代码”。










