我有带有准备好的语句和参数化查询的查询。但在 sonarqube 方面仍然失败并给出了查询安全问题。我不知道我的查询中什么不安全
这是代码:
let { keyword } = req.query;
const first_query = `
SELECT hs_code, tree_id, CONCAT(hs_code, ' - ', tree_id)
AS gabungan FROM referensi.v_btbmi_2022 vb
`;
const option =
keyword.length < 1
? 'false'
: '(tree_id ILIKE :keyword OR hs_code ILIKE :keyword)';
if (keyword.length < 1) {
res.status(400).json({
code: "03",
message: "data inputan tidak ada",
data: [],
});
return;
}
const last_query = await db.query(
first_query + ' WHERE LENGTH(hs_code) > 7 AND ' + option,
{
replacements: { keyword: `%${keyword}%` },
type: db.QueryTypes.SELECT,
},
);
我是后端开发的新手,认为这个查询足够安全。如何改进查询使其真正安全并且可以通过sonarqube?
我相信您展示的代码没有安全漏洞。
我不使用 Sonarqube,但我相信它注意到您的查询的一部分是通过字符串与您的
option
变量连接形成的。它有一个简单的规则,即使用串联格式化 SQL 查询“可能”存在 SQL 注入风险,因此它将此代码标记为有风险。
但是,在您的情况下,您的 option
变量只能是“false”或“(tree_id ILIKE :keyword OR hs_code ILIKE :keyword)”——这两个值在代码中都是明确的,并且不会受到不受信任的输入的影响。所以很安全。
Sonarqube 显然无法理解这一点,因此您可能必须通过避免严格的串联来重组代码以满足 Sonarqube 的要求。此外,您的代码逻辑似乎是多余的。如果
keyword.length < 1
,则将
option
设置为 false。但在相同的条件下,您会立即返回状态 400。当 option
为 false 时,您的代码永远不会运行查询,因此 option
变量没有任何用途。我建议尝试这样:
let { keyword } = req.query;
if (keyword.length < 1) {
res.status(400).json({
code: "03",
message: "data inputan tidak ada",
data: [],
});
return;
}
const first_query = `
SELECT hs_code, tree_id, CONCAT(hs_code, ' - ', tree_id)
AS gabungan FROM referensi.v_btbmi_2022 vb
WHERE LENGTH(hs_code) > 7 AND (tree_id ILIKE :keyword OR hs_code ILIKE :keyword)
`;
const last_query = await db.query(first_query,
{
replacements: { keyword: `%${keyword}%` },
type: db.QueryTypes.SELECT,
},
);
这将完整的 SQL 查询定义为固定字符串,不使用字符串连接进行格式化。