基于Node Express+mssql的多词查询是否存在SQL注入风险?
多词搜索的SQL注入风险与参数化查询实现
你的问题场景
我正在开发支持多词搜索的搜索栏,担忧存在SQL注入问题。我使用Node Express框架搭配npm的mssql包,当前实现代码如下:
router.get('/search/:criteria', function (req, res) { var criteria = req.params.criteria; var words = criteria.split(" "); var x = "" words.map(word => x += `name like '%${word}%' and `); x = x.substring(0, x.length - 5); // Remove trailing 'and' var query = `SELECT * FROM table WHERE ${x}` new sql.ConnectionPool(db).connect().then(pool => { return pool.request().query(query) }).then(result => { // 处理结果 }) });
当搜索内容为something to search时,生成的SQL语句为:
SELECT * FROM table WHERE name like '%something%' and name like '%to%' and name like '%search%'
我自行测试了部分SQL注入手段,但似乎都无效。
说明:我知晓应始终使用参数化查询,单单词场景下该方式可行,但不清楚多词场景下如何实现参数化查询,示例如下:
new sql.ConnectionPool(db).connect().then(pool => { return pool.request() .input('input', '%'+criteria+'%') .query(query) })
请问当前生成的查询语句在SQL注入方面安全性如何?
我的解答
先给结论:当前代码完全不安全
你觉得测试注入无效只是运气好而已,咱们举个实际的注入例子:如果用户搜索的内容是 test' OR 1=1-- ,拆分后这个“单词”会被直接拼进SQL语句,最终生成的查询会变成:
SELECT * FROM table WHERE name like '%test' OR 1=1-- %'
这里的--是SQL注释符,后面的内容会被忽略,所以这条语句等价于SELECT * FROM table WHERE name like '%test' OR 1=1,会直接返回表中所有数据。如果数据库权限够高,恶意用户甚至可以构造输入来删除数据、篡改表结构,风险极大。直接拼接用户输入到SQL语句里是绝对的禁忌,没有任何例外。
多词场景的参数化查询实现
其实mssql包支持动态添加多个参数,咱们可以循环处理每个搜索词,给每个词创建独立的参数,彻底隔离用户输入和SQL结构:
router.get('/search/:criteria', async function (req, res) { try { const criteria = req.params.criteria; // 先过滤掉空词,避免生成无效的SQL条件 const words = criteria.split(" ").filter(word => word.trim() !== ""); if (words.length === 0) { // 处理空搜索的情况,比如返回空结果或者提示用户输入关键词 return res.json([]); } // 初始化连接池和请求对象 const pool = await new sql.ConnectionPool(db).connect(); const request = pool.request(); // 构建参数化的查询条件数组 const conditions = []; words.forEach((word, index) => { // 给每个参数起唯一的名字,比如word0、word1 const paramName = `word${index}`; // 把条件加入数组,用@参数占位符 conditions.push(`name LIKE @${paramName}`); // 绑定参数值,把通配符%和用户输入拼接后作为参数值传入 request.input(paramName, sql.VarChar, `%${word}%`); }); // 拼接最终的SQL查询语句 const query = `SELECT * FROM table WHERE ${conditions.join(' AND ')}`; // 执行查询 const result = await request.query(query); // 返回查询结果 res.json(result.recordset); } catch (err) { // 完善的错误处理,避免服务器崩溃 console.error('搜索出错:', err); res.status(500).send('搜索服务暂时不可用'); } finally { // 确保关闭SQL连接 await sql.close(); } });
这个实现的核心优势
- 彻底杜绝SQL注入:每个搜索词都是独立的参数,数据库会把参数值当作纯文本处理,不会解析成SQL语句的一部分
- 代码更清晰:用
async/await替代Promise链式调用,可读性和可维护性更好 - 鲁棒性更强:过滤了空词,处理了空搜索的情况,还有完善的错误捕获
额外提醒
- 永远不要依赖“用户输入看起来无害”这种假设,所有用户输入都要当作恶意的来处理
- 预处理用户输入(比如过滤特殊字符)只能作为辅助手段,绝对不能替代参数化查询
- 尽量使用
async/await来处理异步操作,比Promise链式调用更直观
内容的提问来源于stack exchange,提问作者Sir Rubberduck
相关产品推荐
相关产品推荐

