Node.js使用${variable}拼接SQL查询的注入风险及解决办法
问题解答
首先明确结论:你当前的代码写法存在明确的SQL注入风险,你对微软官方文档的描述存在误解。
风险原因说明
你贴的微软官方文档里的安全声明,仅适用于使用驱动内置的参数化查询接口传参的场景,你现在直接通过JS模板字符串将变量${userData.plid}、${userId}拼接进SQL语句的做法,完全绕过了驱动的自动安全校验逻辑,等于直接把用户可控的输入拼到执行语句中,一旦输入值被攻击者篡改,即可执行任意恶意SQL语句。
不建议自行做SQL内容sanitize
手动实现SQL内容转义的风险极高,目前存在大量绕过手动转义的技术手段,包括特殊编码绕过、字符集溢出绕过等,自行实现的sanitize逻辑无法覆盖所有攻击场景,会给业务留下长期的安全隐患。
低改造成本的安全方案
你应该是使用Node的mssql库操作SQL Server,该库本身支持极简的参数化查询写法,不需要你手动编写DECLARE定义参数,仅需要两步改造即可:
- 将SQL语句中原本拼接变量的位置替换为
@参数名占位符 - 调用
query方法时,第二个参数传入参数键值对对象
示例改造如下:
改造前代码:
let sqlString = `select * from table where userid=${userId}` let conn = await sql.connect(process.env.DB_CONNSTRING) let recordset = await conn.query(sqlString)
改造后代码:
// 仅替换变量位置为占位符 let sqlString = `select * from table where userid=@userId` let conn = await sql.connect(process.env.DB_CONNSTRING) // 新增第二个参数传参,驱动自动做安全处理 let recordset = await conn.query(sqlString, { userId })
这种写法完全符合你贴的微软官方文档的安全规则,驱动会自动将参数作为预编译语句的输入处理,完全杜绝SQL注入风险。针对你提到的多依赖查询的场景,参数化查询完全不会影响你的执行顺序,你依然可以按原有逻辑用await依次执行各个查询。
整体改造量极小,全局搜索SQL语句中的${即可定位所有需要修改的插值点,50个路由的改造通常半小时内即可完成,远低于你开发、测试自定义sanitize逻辑的成本,安全保障性也高得多。
内容的提问来源于stack exchange,提问作者Pablo Varela
相关产品推荐
相关产品推荐

