Node.js 连接 MySQL 时如何防止 SQL 注入

SQL 注入长期位居 OWASP Top 10 榜单前列,而 Node.js 作为高并发后端的热门选择,其与 MySQL 的交互安全性直接关系到整个应用的数据底线。很多开发者以为用了 ORM 就万事大吉,或者觉得参数化查询“太麻烦”,结果在生产环境埋下致命隐患。本文从攻击原理出发,结合 Node.js 生态的实际代码,系统梳理防止 SQL 注入的几种可靠方案。

SQL 注入为什么在 Node.js 中同样危险

SQL 注入的本质是用户输入被当作 SQL 代码执行。在 Node.js 中,常见的高危写法是字符串拼接:

const sql = `SELECT * FROM users WHERE name = '${req.query.name}'`;
connection.query(sql, (err, results) => { ... });

当攻击者传入 ' OR '1'='1 时,查询条件恒真,可绕过登录验证;传入 '; DROP TABLE users; -- 则可能直接删表。Node.js 的异步特性并不会降低这种风险,反而因为回调嵌套容易让开发者忽略输入来源的校验。

方案一:使用参数化查询(预处理语句)

这是最推荐、最有效的方式。MySQL 驱动 mysqlmysql2 都支持占位符 ?,驱动会将参数与 SQL 模板分开传输,数据库先编译 SQL 结构,再填入数据,从根本上杜绝注入。

const sql = 'SELECT * FROM users WHERE name = ? AND password = ?';
connection.query(sql, [req.body.name, req.body.password], (err, results) => {
  // 即使传入 ' OR '1'='1,也只会被当作普通字符串匹配
});

使用 mysql2/promise 版本时写法更清晰:

const [rows] = await connection.execute(
  'SELECT * FROM users WHERE id = ?',
  [userId]
);

注意:表名、列名、ORDER BY 字段不能用 ? 占位,这些属于 SQL 结构部分。如果确实需要动态排序,必须用白名单校验:

const allowedColumns = ['id', 'name', 'created_at'];
const orderBy = allowedColumns.includes(req.query.sort)
  ? req.query.sort
  : 'id';
const sql = `SELECT * FROM users ORDER BY ${orderBy} DESC`;

方案二:使用 ORM 或 Query Builder

Sequelize、TypeORM、Knex.js 等工具默认使用参数化查询,能大幅减少手写 SQL 的风险。

// Sequelize
await User.findOne({ where: { name: req.body.name } });

// Knex
await knex('users').where('name', req.body.name).first();

但要注意:ORM 的 raw 方法或 whereRaw 如果拼接了用户输入,同样会引入注入。例如 knex.raw(\SELECT * FROM users WHERE name = '${name}'`)` 就是典型的错误用法。

方案三:输入校验与最小权限原则

参数化查询是核心防线,但纵深防御同样重要:

  • 输入校验:对邮箱、手机号、ID 等字段用 validatorjoi 做格式校验,拒绝不符合预期的输入。
  • 最小权限:连接 MySQL 的账号只授予必要权限。应用账号不应拥有 DROPFILEGRANT 等权限,即使被注入,损失也可控。
  • 错误信息脱敏:不要把数据库原始错误直接返回给前端,避免泄露表结构。
  • 转义函数mysql.escape() 可作为兜底,但不应作为主要手段,因为它容易遗漏。

关联安全话题速览

XSS 的常见方式和前端如何防御

XSS 与 SQL 注入常在同一应用中并存。常见方式包括反射型(恶意链接)、存储型(评论注入)和 DOM 型(前端脚本拼接)。前端防御要点:对用户内容输出时使用 textContent 而非 innerHTML;使用 DOMPurify 等库净化富文本;设置 Content-Security-Policy 响应头限制脚本来源;Cookie 加 HttpOnly 防止脚本读取。

MySQL 防止 SQL 注入的几种写法

在数据库层面,除了应用层参数化,还可以:使用存储过程并配合参数绑定;对数据库账号做权限隔离;开启 sql_mode 严格模式减少隐式转换;审计慢查询日志发现异常 SQL。但核心仍是应用层不拼接用户输入。

Linux 服务器安全加固清单

数据库安全离不开主机安全:及时更新系统补丁;禁用 root 远程登录,改用密钥认证;配置防火墙仅开放必要端口(如 3306 不对外网开放);使用 fail2ban 防暴力破解;定期审计 authorized_keys 和定时任务;对数据库备份文件加密存储。

总结

Node.js 连接 MySQL 防注入,记住三条铁律:永远用参数化查询,永远不拼接用户输入,永远给数据库账号最小权限。ORM 和 Query Builder 能降低出错概率,但不能替代安全意识。把参数化查询作为默认习惯,再配合输入校验和权限隔离,才能让应用在真实攻击面前站得住脚。

未经允许不得转载:任鹏个人博客 » Node.js 连接 MySQL 时如何防止 SQL 注入

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏