我目前正在开发一个nodejs后端脚本,该脚本解析传入的http请求,以便在mysql数据库中进行写操作和读操作。我试图通过使用一种两层保护来防止sql注入。
要写入数据库,用户需要提供有效的json。这就是json的键对于脚本写入db的方式。如果没有,请求将被取消。
{
"uuid": "1234-5678-abcd-efgh",
"product_id": 6,
"product_extras": "color=red",
"product_count": 2,
"buyer_name": "X Y",
"shipping_address": "XY Street 5"
}
检查这个输入的第一层是一个非常基本的黑名单。在这里 USER_INPUT
变量是上面已经通过验证过程的json。
let BLACKLIST = ["DROP ", "DELETE ", "INSERT ", "UPDATE ", "SELECT ", "WHERE ", "ALTER "];
let dont_execute = false;
for(var i = 0; i < BLACKLIST.length; i++) {
if(JSON.stringify(USER_INPUT).toUpperCase().includes(BLACKLIST[i].toUpperCase())) {
console.log("\x1b[31mreceived blacklisted command - aborting");
dont_execute = true;
return false;
}
}
在验证之后,如果 dont_execute
如果仍然为false,则将调用第二层,因此将转义查询并发送,如下所示:
// setting.sqlconnection.table_name is equal to "orders" in this case. Also this variable can't be changed or specified by the user. It's pulled from a settings.json file
sql.sendQuery("INSERT INTO " + setting.sqlconnection.table_name + " (uuid, productid, orderid, productextras, productcount, buyername, shippingaddress) VALUES (" + sqlconnection.escape(uuid) + ", " + sqlconnection.escape(parseddata.product_id) + ", " + null + ", " + sqlconnection.escape(parseddata.product_extras) + ", " + sqlconnection.escape(parseddata.product_count) + ", " + sqlconnection.escape(parseddata.buyer_name) + ", " + sqlconnection.escape(parseddata.shipping_address) + ")");
我尝试过很多不同的注射方法,比如这个:
{
"uuid": "1234-5678-abcd-efgh",
"product_id": 6,
"product_extras": "color=red",
"product_count": 2,
"buyer_name": "X Y",
"shipping_address": "');DROP orders;--"
}
正如我所料,它没有工作,因为首先它是在第一个黑名单层咳嗽。但是在禁用它只是为了测试之后,整个sql查询就像一个字符串一样被解释为撇号被转义( '
成为 \'
),这正是我想要的。据我所知,将与受sqli感染的json一起发送的查询最终将如下所示:
INSERT INTO orders (guid, productid, orderid, productextras, productcount, buyername, shippingaddress) VALUES ("1234-5678-abcd-efgh", 6, null, "color=red", 2, "X Y", "\');DROP orders--")
但问题是,在向我的老板展示了这个之后,他说它不安全,而且它仍然容易受到sqli的攻击。所以我的问题是,如果他是对的,如果是的话,我可以做些什么来改进它。
其他信息:
我正在使用npm包 mysql
对于数据库连接
我使用xampp和mysql在本地托管数据库
我很抱歉,如果我不能提供更多的信息,但我很肯定,我不允许张贴更多的东西比这个。
1条答案
按热度按时间isr3a4wc1#
无神论的方法肯定会漏掉一些案例。您需要更多地研究查询是如何形成的,您应该为您的代码编写完整的单元测试,这样任何查看您的代码的人都可以看到您测试过哪些情况。
denylist方法也会得到假阳性。例如,似乎无法插入包含单词“drop”的任何数据。这将阻止一些合法的数据值。
这两个问题都是通过使用参数化查询来解决的,正如上面的评论所建议的。您说过您将“看一看”如何使用参数,但您应该将其视为防止sql注入的主要解决方案,而不是任何可选或高级用法。
但是,参数只能用于替代标量值(字符串、数字、日期)。不能对表名、列名或其他标识符、sql表达式或sql关键字使用参数。这些情况可能不太常见,但在动态表名称中至少有一个示例。
有害的输入不仅仅来自用户。它可以来自文件、web服务和json文档。它甚至可以来自你自己的数据库!任何可能包含奇怪字符的内容都可能导致sql注入。
sql注入并不一定是恶意的。这可能只是一个错误,更可能导致sql查询无效,而不是导致数据泄露。
补充参数化查询的解决方案通常是允许的。例如,如果怀疑配置文件中的表名是否合法,请对照已知表名列表进行检查。一些应用程序将此作为一个常量数组。一些应用程序查询信息模式以获取最新的表列表。
在电子商务数据库中见过名为
ORDER
? 这会导致sql变得混乱,因为ORDER
是一个保留字。您应该在后面的记号中分隔表名,以防它们是sql保留字或包含标点或空格。下面是在表名周围添加回勾的示例: