mysql - Avoiding SQL Injections to the Stored Procedure in Node.js
问题描述
How to avoid SQL injections from Node.js when the calls are made to the stored procedure
Suppose from the front End of the UI if I entered some special characters
Eg.:
If
?
is enteredtrue
will be saved to the databaseIf
??
is entered`true`
will be saved to the database
For some special characters such as Backslashes(\
) and Apostrophes ('
)
I will be getting these types of errors from the console
From console: '
{ Error: ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near
'''')' at line 1
at Query.Sequence._packetToError (C:\xampp\htdocs\nodechat\node_modules\mysql\lib\protocol\sequences\Sequence.js:47:14)
at Query.ErrorPacket (C:\xampp\htdocs\nodechat\node_modules\mysql\lib\protocol\sequences\Query.js:77:18)
at Protocol._parsePacket (C:\xampp\htdocs\nodechat\node_modules\mysql\lib\protocol\Protocol.js:278:23)
at Parser.write (C:\xampp\htdocs\nodechat\node_modules\mysql\lib\protocol\Parser.js:76:12)
at Protocol.write (C:\xampp\htdocs\nodechat\node_modules\mysql\lib\protocol\Protocol.js:38:16)
at Socket.<anonymous> (C:\xampp\htdocs\nodechat\node_modules\mysql\lib\Connection.js:91:28)
at Socket.<anonymous> (C:\xampp\htdocs\nodechat\node_modules\mysql\lib\Connection.js:502:10)
at Socket.emit (events.js:182:13)
at addChunk (_stream_readable.js:283:12)
at readableAddChunk (_stream_readable.js:264:11)
--------------------
at Protocol._enqueue (C:\xampp\htdocs\nodechat\node_modules\mysql\lib\protocol\Protocol.js:144:48)
at Connection.query (C:\xampp\htdocs\nodechat\node_modules\mysql\lib\Connection.js:200:25)
at Object.saveFeeds (C:\xampp\htdocs\nodechat\middleware\db.js:96:15)
at C:\xampp\htdocs\nodechat\middleware\routes.js:187:12
at Layer.handle [as handle_request] (C:\xampp\htdocs\nodechat\node_modules\express\lib\router\layer.js:95:5)
at next (C:\xampp\htdocs\nodechat\node_modules\express\lib\router\route.js:137:13)
at Route.dispatch (C:\xampp\htdocs\nodechat\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (C:\xampp\htdocs\nodechat\node_modules\express\lib\router\layer.js:95:5)
at C:\xampp\htdocs\nodechat\node_modules\express\lib\router\index.js:281:22
at Function.process_params (C:\xampp\htdocs\nodechat\node_modules\express\lib\router\index.js:335:12)
code: 'ER_PARSE_ERROR',
errno: 1064,
sqlMessage:
'You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near \'\'\'\')\' at line
1',
sqlState: '42000',
index: 0,
sql: 'CALL AddFeedItems(1,\'\'\')' }
undefined
C:\xampp\htdocs\nodechat\node_modules\mysql\lib\protocol\Parser.js:80
throw err; // Rethrow non-MySQL errors
^
TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be one of type string or Buffer. Received type undefined
at write_ (_http_outgoing.js:595:11)
at ServerResponse.write (_http_outgoing.js:567:10)
at C:\xampp\htdocs\nodechat\middleware\routes.js:188:17
at Query.<anonymous> (C:\xampp\htdocs\nodechat\middleware\db.js:100:13)
at Query.<anonymous> (C:\xampp\htdocs\nodechat\node_modules\mysql\lib\Connection.js:502:10)
at Query._callback (C:\xampp\htdocs\nodechat\node_modules\mysql\lib\Connection.js:468:16)
at Query.Sequence.end (C:\xampp\htdocs\nodechat\node_modules\mysql\lib\protocol\sequences\Sequence.js:83:24)
at Query.ErrorPacket (C:\xampp\htdocs\nodechat\node_modules\mysql\lib\protocol\sequences\Query.js:90:8)
at Protocol._parsePacket (C:\xampp\htdocs\nodechat\node_modules\mysql\lib\protocol\Protocol.js:278:23)
at Parser.write (C:\xampp\htdocs\nodechat\node_modules\mysql\lib\protocol\Parser.js:76:12)
routes.js
app.post('/AddFeedItems', function(req, res) {
// console.log(req.body);
try{
console.log(JSON.parse(Object.keys(req.body)[0]));
req.body = JSON.parse(Object.keys(req.body)[0]);
} catch(err) {
console.log('Error');
req.body = req.body
}
db.saveFeeds(req.body, function(chats) {
res.write(JSON.stringify(chats));
res.end();
})
});
db.js
function saveFeeds(data,cb) {
const conn = createConnection();
conn.connect();
console.log('From console'+data.keyword);
let sql ="CALL AddFeedItems("+data.senderid + ",'" + data.keyword + "')";
conn.query(sql, true,function(err,result) {
if(err) console.log(err);
conn.end();
console.log(result);
cb(result);
});
}
MySQL Stored Procedures
CREATE PROCEDURE `AddFeedItems`(IN `senderid` BIGINT(255), IN `keyword` VARCHAR(255)) NOT DETERMINISTIC CONTAINS SQL SQL SECURITY DEFINER
BEGIN
DECLARE LastFeedId INT;
INSERT INTO `feed_item` (`userid`, `content`, `timestamp`, `likes`, `comments`, `user_flag`, `likes_data`) VALUES (senderid, keyword, CURRENT_TIMESTAMP(), 0, 0, 0, 'like');
SET LastFeedId = LAST_INSERT_ID();
INSERT INTO `feed_item_likes` (`feed_item_id`, `user_id`, `timestamp`, `is_like`) VALUES (LastFeedId, senderid, CURRENT_TIMESTAMP(), 0);
SELECT LastFeedId;
END
In general, In order to prevent these special characters injections into the SQL. What are the necessary steps and precaution should be adopted in the code?
Edit:
Need a function to strip off a set of special character's like Backslashes(\
), Dollars($
), Apostrophes ('
) and Question Marks(?
) from Node.js
So I found the solution to replace all the above special characters, except for the Question Marks(?
).
These were the following results obtained:
With question mark in regex
data.keyword.replace(/[\\$'"\?]/g, "\\$&")
+-----------+-----------+
|Entered |Saved into |
|Character |Database |
+-----------+-----------+
| ? | rue |
| ?? | rue? |
| ??? | ??? |
+-----------+-----------+
Without question mark in regex
data.keyword.replace(/[\\$'"]/g, "\\$&")
+-----------+-----------+
|Entered |Saved into |
|Character |Database |
+-----------+-----------+
| ? | true |
| ?? | `true` |
| ??? | ??? |
+-----------+-----------+
Tried out with built-in functions,
var key = mysql.escape(data.keyword);
var key = conn.escape(data.keyword);
let sql ="CALL AddFeedFriendItems("+data.senderid + "," + data.friendid + ",'" + data.friendusername + "'," + key + ")";
Still the result is not favoring, Question Marks(?
) will be stored as true
.
I need to replace those Question Marks(?
) with only ?
value. Instead, true
or rue
value will be stored into the database.
How am I supposed to write the regex to match the question mark and replace with the same characters only?
Without the MySQL Stored Procedures, replacing the above saveFeeds()
in db.js
Data will be stored in a proper manner
function saveFeeds(data,cb){
const conn = createConnection();
conn.connect();
conn.query(
"INSERT INTO feed_item (userid, content, timestamp, likes, comments, user_flag, likes_data) VALUES (?, ?, ?, ?, ?, ?, ?)", [data.senderid, data.keyword, data.timestamp, 0, 0, 0, 'like'],
function (err, rows) {
if(err) {
console.log(err);
} else {
var feedId = rows.insertId;
var feedId = rows.insertId;
conn.query(
"INSERT INTO feed_item_likes (feed_item_id, user_id, timestamp, is_like) VALUES (?, ?, ?, ?)", [feedId, data.senderid, data.timestamp, 0],
function (err, rows) {
if(err) {
console.log(err);
} else {
var feedId = rows.insertId;
}
}
);
}
conn.end();
cb(feedId);
}
);
}
解决方案
问题不在于您的存储过程,而在于您的 CALL 语句:
sql: 'CALL AddFeedItems(1,\'\'\')' }
这将产生一条 SQL 语句:
CALL AddFeedItems(1,''')
连续三个'
引号不是有效的语法。它在 CALL 语句上引发语法错误,它永远不会超过运行存储过程。
如果您想要一个包含文字单引号的带引号的字符串,则 SQL 必须是以下形式之一:
CALL AddFeedItems(1,'''') -- two single-quotes become one literal single-quote
CALL AddFeedItems(1,'\'') -- escaped single-quote
CALL AddFeedItems(1,"'") -- delimit by alternative quotes, if sql_mode is not ANSI
推荐阅读
- amazon-web-services - 从在另一个 AWS 账户中运行的 lambda 更新 SSM 参数?
- python - 如何将字典转换为数据框并爆炸
- c# - 保存搜索字符串以在 ASP.NET Core Web 应用程序的其他 cshtml 页面中使用
- stripe-payments - 如何识别试用结束后开始付款订阅的 Stripe 客户
- c# - .Net Core SignOut() RedirectUri 不起作用
- javascript - 在 React Native 和 Nodejs 中点击支付网关
- javascript - precacheAndRoute 在 addToCacheList 上出错
- python-3.x - 如何使用正则表达式获取此字符串的 asin?
- javascript - 我可以在 React Provider 中进行 api 调用吗?
- c# - UWP 拦截 Webview POST 请求并获取内容