Как избежать SQL-инъекций в хранимую процедуру в Node.js - PullRequest
0 голосов
/ 02 февраля 2019

Как избежать SQL-инъекций из Node.js, когда выполняются вызовы хранимой процедуры

Предположим, из внешнего интерфейса пользовательского интерфейса, если я ввел некоторые специальные символыНапример.:

  • Если введено ? true будет сохранено в базе данных

  • Если введено ??, будет `true`сохранено в базе данных

Для некоторых специальных символов, таких как обратная косая черта (\) и Апострофы (')

Я будуполучение этих типов ошибок из консоли

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)

rout.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

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

В общем, для предотвращения внедрения этих специальных символов в SQL.Какие необходимые шаги и меры предосторожности следует принять в коде?


Редактировать:

Нужна функция для удаления набора специальных символов, таких как обратная косая черта (\), доллары ($), апострофы (') и вопросительные знаки (?) от Node.js

Итак, я нашел решение заменить все вышеперечисленные специальные символы, кроме знаков вопроса (?).

Были получены следующие результаты:

С вопросительным знаком в регулярном выражении

data.keyword.replace(/[\\$'"\?]/g, "\\$&")

+-----------+-----------+
|Entered    |Saved into |
|Character  |Database   |
+-----------+-----------+
| ?         | rue       |
| ??        | rue?      |
| ???       | ???       |
+-----------+-----------+

Без знака вопроса в регулярном выражении

data.keyword.replace(/[\\$'"]/g, "\\$&")

+-----------+-----------+
|Entered    |Saved into |
|Character  |Database   |
+-----------+-----------+
| ?         | true      |
| ??        | `true`    |
| ???       | ???       |
+-----------+-----------+

Пробовал со встроенными функциями,

  1. var key = mysql.escape(data.keyword);
  2. var key = conn.escape(data.keyword);
let sql ="CALL AddFeedFriendItems("+data.senderid + "," + data.friendid + ",'" + data.friendusername + "'," + key + ")";

Тем не менее, результат не благоприятствует, вопросительные знаки (?) будут сохранены как true.

Мне нужно заменить эти вопросительные знаки (?) только значением ?.Вместо этого в базу данных будет сохранено значение true или rue.

Как мне записать регулярное выражение всопоставить знак вопроса и заменить только теми же символами?


Без хранимых процедур MySQL, заменив вышеприведенные saveFeeds() в db.js

Данные будут храниться надлежащим образом

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);
            }
          );
}

Ответы [ 2 ]

0 голосов
/ 08 февраля 2019

Кроме того, я нашел решение с помощью Regex + Unicode + Встроенная функция

var key = conn.escape(data.keyword);
var keyword = key.replace(/[?]/g, "❓");

let  sql ="CALL AddFeedFriendItems("+data.senderid + "," + data.friendid + ",'" + data.friendusername + "'," + keyword + ")"; 

Список символов Unicode с вопросительным знаком

По умолчанию сортировка будетбыть установлен на latin1_swedish_ci в MySQL.Это сбивает с толку, какой тип символов для сохранения.Поэтому, естественно, он будет сохранен в текстовом формате ?.Хотя в общем случае любой символ Unicode ? будет сохранен в БД.Поскольку для параметра Collation установлено значение latin1_swedish_ci

Примечание. Необходимость изучения сохранения символов Unicode в MySQL снизит производительность или приведет к извлечению записей по индексу B-Tree, что вызовет любые другие проблемы.Поскольку .replace() приведет к дальнейшему снижению производительности, если будет храниться более 999 КБ сообщений.Потому что по умолчанию Collation будет установлен на latin1_swedish_ci в MySQL

0 голосов
/ 02 февраля 2019

Проблема не в вашей хранимой процедуре, а в вашем операторе 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...