You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:10:28