存储过程真能防住SQL注入吗?我这样写安全吗?

UX-米阳 阅读 34

我在用Node.js调用MySQL的存储过程,听说用存储过程能防SQL注入,但我还是有点不放心。比如我这样拼接参数传进去:

CALL getUserInfo(${userId})

会不会有风险?是不是必须用参数化调用才行?之前试过直接拼字符串,结果被同事说有安全隐患。

我来解答 赞 5 收藏
二维码
手机扫码查看
2 条解答
UI瑞君
UI瑞君 Lv1
存储过程确实能在一定程度上防止SQL注入,但你这样直接拼接参数进去还是有风险的。在JS里面,最好用参数化调用来保证安全。

比如说你可以这样写:

const userId = 123;
const query = 'CALL getUserInfo(?)';
connection.query(query, [userId], (error, results) => {
if (error) throw error;
console.log(results);
});


这里用问号占位符来代替直接拼接参数。虽然存储过程内部已经做了很多封装,但外部传参的时候还是要小心,不然万一存储过程里面有动态SQL拼接,那你的参数就可能被恶意利用了。

说实话,我以前也图省事直接拼字符串,后来踩过坑才知道这玩意儿真不能马虎。现在不管是存储过程还是普通查询,一律参数化调用,心里踏实多了。
点赞
2026-04-01 03:01
长孙光磊
你这样写不安全,CALL getUserInfo(${userId}) 这种直接拼接的方式跟普通SQL注入没区别,存储过程白写了。

存储过程防注入的原理是:参数在存储过程内部是作为参数传递的,SQL引擎会把它当成数据处理,而不是SQL代码的一部分。但前提是你得用参数化的方式调用它。

你这种写法相当于在SQL字符串里直接插变量,攻击者只要传 1; DROP TABLE users; -- 这样的值,照样注入成功。

正确写法应该是用预处理语句传参,以node-mysql2为例:

// 错误的写法(你现在的)
await connection.execute(CALL getUserInfo(${userId}));

// 正确的写法
await connection.execute('CALL getUserInfo(?)', [userId]);


存储过程本身没问题,但你调用它的方式得对。参数占位符 ? 会让驱动把 userId 当成纯数据传进去,就算里面包含SQL关键字也不会被执行。

另外提醒一下,光靠存储过程也不是万能的。如果你的存储过程内部还在动态拼接SQL(比如用 CONCAT 拼查询条件),那该注入还是注入。最佳实践是:存储过程用参数,应用程序层也用参数化查询,双重保险。
点赞
2026-03-12 20:02