我目前正在研究NodeJS后端脚本,该脚本解析传入的HTTP请求以写入和读取MySQL数据库以进行工作。我试图通过使用一种两层保护来防止SQL注入。
要写入数据库,用户需要提供有效 JSON。这就是 JSON的键才能使脚本写入数据库的方式。如果没有,请求将被取消。
{
"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查询就像一个撇号一样被解释为一个转义符('
变成了\'
),这正是我想要的。据我所知,将使用受SLQI感染的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一起用于在本地托管数据库
很抱歉,我无法提供更多信息,但是我很确定我不允许发布更多内容。
答案 0 :(得分:1)
黑名单方法肯定会遗漏某些情况。您需要更多地研究查询的形成方式,并且应该为代码编写全面的单元测试,以便任何查看您的代码的人都可以看到您测试过的情况。
黑名单方法也将获得误报。看来您无法插入任何包含单词“ DROP”的数据。这将阻止一些合法的数据值。
这两个问题都可以通过使用参数化查询来解决,如上面的注释所建议。您说过要“看一下”使用参数,但是应该将其视为用于防止SQL注入的 primary 解决方案,而不是任何可选的或高级的用法。
但是,参数仅在代替标量值(字符串,数字,日期)时才有用。您不能将参数用于表名或列名或其他标识符,SQL表达式或SQL关键字。这些情况可能不太常见,但是动态表名称中至少有一个示例。
有害的输入不仅来自用户。它可以来自文件,Web服务或JSON文档。它甚至可以来自您自己的数据库!任何可能包含奇怪字符的内容都可能导致SQL注入。
SQL注入不一定是恶意的。只是一个错误,很可能导致您的SQL查询无效,而不是导致数据泄露。
补充参数化查询的解决方案通常是白名单。例如,如果您想知道配置文件中的表名是否合法,请对照已知表名列表进行检查。一些应用程序将此保持为恒定数组。一些应用程序查询INFORMATION_SCHEMA以获得表的最新列表。
是否曾经在名为ORDER
的电子商务数据库中看到一个表?这将导致SQL变得混乱,因为ORDER
是保留字。
如果表名是SQL保留字或包含标点符号或空格,则应使用反引号分隔表名。
下面是在表名周围添加反引号的示例:
sql.sendQuery("INSERT INTO `" + setting.sqlconnection.table_name + "` (uuid, ...