Prevent SQL Injection in JavaScript / Node.js - javascript

I am using Node.js to create a Discord bot. Some of my code looks as follows:
var info = {
userid: message.author.id
}
connection.query("SELECT * FROM table WHERE userid = '" + message.author.id + "'", info, function(error) {
if (error) throw error;
});
People have said that the way I put in message.author.id is not a secure way. How can I do this? An example?

The best way to is to use prepared statements or queries (link to documentation for NPM mysql module: https://github.com/mysqljs/mysql#preparing-queries)
var sql = "SELECT * FROM table WHERE userid = ?";
var inserts = [message.author.id];
sql = mysql.format(sql, inserts);
If prepared statements is not an option (I have no idea why it wouldn't be), a poor man's way to prevent SQL injection is to escape all user-supplied input as described here: https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet#MySQL_Escaping

Use prepared queries;
var sql = "SELECT * FROM table WHERE userid = ?";
var inserts = [message.author.id];
sql = mysql.format(sql, inserts);
You can find more information here.

Here is the documentantion on how to properly escape any user provided data to prevent SQL injections: https://github.com/mysqljs/mysql#escaping-query-values .
mysql.escape(userdata) should be enough.

Related

how to sanitize sql.js inputs?

I am using sql.js to manage the SQLite file I created for an electron app. My issue is that I want to make sure all the inputs are sanitized. As of now, I am using statements like so:
const SQL = await sqljs();
const db = new SQL.Database();
// These values are just examples and will be user inputs through electron.
let id = 1;
let name = 'row name';
db.run(`INSERT INTO tableName VALUES (${}, 'hello');`);
I'm pretty sure that this way is unsafe and can cause SQL injections. What can I do to prevent such a problem? Thank you kindly.
You can use bound parameters. These are values that are passed to the database engine and not parsed as part of a SQL statement:
let id = 1;
let name = 'row name';
/* Either pass in a dictionary to use named bound parameters */
db.run("INSERT INTO tableName VALUES(:id, :name)", { ':id': id, ':name': name });
/* Or an array to use positional bound parameters */
db.run("INSERT INTO tableName VALUES(?, ?)", [id, name]);
More information is available in the SQLite documentation, as well as sqljs documentation.

How to verify that a a user string input doesn't contain sql injection? in Javascript

I tried to dig in the sanitize function but i didn't find the answer that I wanted, the question is how to check if a user input doesn't contain any sql injection? i'm using Nest JS (similar to node) if you have any idea of how I can do that it would help me a lot!
Generally speaking: You can't. Any input which might be SQL injection could, conceivably, also be genuine input (at least in certain narrow circumstances).
Don't try to detect SQL injection. Instead, use placeholders where possible and proper escaping where not.
The issue is not on the NestJS side, it is on how you build the SQL query to execute.
You may use #nearform/sql that:
A simple SQL injection protection module that allows you to use ES6 template strings for escaped statements. Works with pg, mysql and mysql2 library.
It will protect you against malicious users input.
This module is battle-tested and already in production for Covid Government Tracker.
You can use prepared statements to avoid sql injection attacks
This blog post explains it quite well. for reference a snippet from the post.
function authenticate(req, res, next){
const username = req.query.username,
password = req.query.password
let preparedStatement = new sql.PreparedStatment(),
sqlQuery = "select * from users where (username = #username and password = #password)"
preparedStatement.input('username', sqlVarChar(50))
preparedStatement.input('password', sqlVarChar(50))
preparedStatement.prepare(sqlQuery)
.then(function(){
return preparedStatement.execute({username: username, password: password})
.then(function(recordset){
if(recordset.length == 1){
loggedIn = true
//successful log in
} else {
//authentication failed
}
})
})
.catch(next)
}

Error using mysql in an AWS Lambda function

I have created an AWS Lambda function to retrieve info from an AWS RDS Database. I have also created an API in AWS API Gateway that triggers the Lambda function. The API works fine when my SQL statement is "select * from user". However, when I try something like "select * from user with tag = people", I get this error:
{"errorType":"Error","errorMessage":"You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'tag = 'people'' at line 1","trace":["Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'tag = 'people'' at line 1"," at PromisePool.query (/var/task/node_modules/mysql2/promise.js:330:22)"," at Runtime.module.exports.handler (/var/task/index.js:19:38)"," at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)"]}
My AWS Lambda function defined as (Node.js 12.x):
const mysql = require('mysql2');
const pool = mysql.createPool({
host: process.env.LAMBDA_HOSTNAME,
user: process.env.LAMBDA_USERNAME,
password: process.env.LAMBDA_PASSWORD,
database: process.env.LAMBDA_DATABASE,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
module.exports.handler = async (event, context, callback) => {
context.callbackWaitsForEmptyLoop = false;
const tag = event["params"]["querystring"]["tag"]
const sql = "select * from user with tag = " + tag;
const promisePool = pool.promise();
const [rows] = await promisePool.query(sql);
const lambdaProxyResponse = {
statusCode: 200,
body: JSON.stringify([rows])
};
return lambdaProxyResponse;
};
Can someone help me out with this issue? Also when I run the command in mysql workbench, it executes correctly.
I'm not positive what your overall environment looks like but first and foremost it's not a great idea to compose your own SQL this way. This code could potentially be subject to a SQL injection attack.
But, assuming you trust the input, it's a pretty simple fix. You need quotes:
const sql = "select * from user with tag = '" + tag + "'";
Note that this is true when the column is a string type. On an numeric type you would not need the quotes.
If you don't trust the input then you need to look at using prepared statements of some sort.

How to escape mysql special characters with sockets.io/node.js/javascript

I am using sockets.io to insert user-generated messages into MySQL, but I'm running into issues inserting records with an apostrophe. I've been trying to use the replace() method on the client side script, but the input text is passing with the apostrophe.
socket.on('refresh feed',function(msg){
str=msg.replace("'", "\'");
alert(str);
$("#chtxt").append(str + '<br />');
});
The above attempt will alert any string without the special character, but does not alert when it exist. I believe that I'm actually alerting after the message has been sent to sockets.
So, I tried adapting this code which watches for the enter key press to also watch for the apostrophe, with no luck there either.
$('#omnibox').keypress(function (e) {
var key = e.which;
if(key == 13) // the enter key code
{
$('input[name = "clicky"]').click();
return false;
}
if(key == 222) // the apostrophe key code
{
alert('Apostrophe!')
return false;
}
});
I researched the question of how to replace special characters for MySQL using javascript but found outdated stacks explaining why client-side validation for this is not a good idea.
That's fine. If I shouldn't do this client side, I need to know then how to do it in my server.js node script, then. It is still javascript, so a solution on either side, provided it's secure would be great.
Server-side code:
var add_status = function (status,callback) {
pool.getConnection(function(err,connection){
if (err) {
callback(false);
return;
}
connection.query("INSERT INTO `videosub` (`url`) VALUES ('"+status+"')",function(err,rows){
connection.release();
if(!err) {
callback(true);
}
});
connection.on('error', function(err) {
callback(false);
return;
});
});
}
Thanks!
Don't do it
You are asking about the wrong solution to the problem.
To replace the apostrophes with backslash-apostrophes you might use:
str = msg.replace(/'/g, '\\\'');
but you should not do that. I am only providing that info because that's what your question asks about but read below.
Why it's a bad idea
You shouldn't do it on the client side and you shouldn't do in on the server side either. If avoiding SQL injection vulnerabilities was a simple matter of replacing apostrophes with backslash-apostrophes then it wouldn't be an issue. Unfortunately it's more complicated.
Having the info that you provided it's even impossible to tell whether backslash-apostrophe would even do what you expect in the first place without seeing your code that actually makes the database queries. But it doesn't matter because you should never ever do that. Never. See those answers to see why - those questions are not about SQL injections but the code examples included SQL injection vulnerabilities and the answers explain it:
cannot use backtick when using nodejs 7.3.0
Node js - Promise Rejection Warning when process a lot of data
Is it possible to listen for object instantiation in Node.js?
Obligatory comic strip
What you should do instead
That having been said, you didn't tell what module you're using to query the database but no matter if you're using the mysql module or Sequelize or anything worth its salt, there should always be a mechanism of interpolating variables in a safe manner without manually escaping and concatenating the strings.
Examples
You didn't show even a single line of code that is relevant here so I cannot tell you how to fix it but consider this example:
Unsafe:
connection.query(
"SELECT * FROM player WHERE nick = '"
+ data.login + "' AND pass = '" + data.pass + "'",
function (err, rows) {
//...
}
);
Still unsafe, complex, unreadable, unmaintainable and unreliable:
connection.query(
"SELECT * FROM player WHERE nick = '"
+ data.login.replace(/'/g, '\\\'') + "' AND pass = '" + data.pass.replace(/'/g, '\\\'') + "'",
function (err, rows) {
//...
}
);
Safe and simple:
connection.query(
"SELECT * FROM player WHERE nick = ? AND pass = ?", [data.login, data.pass],
function (err, rows) {
// ...
}
);
More info
For more info see the docs:
https://www.npmjs.com/package/mysql
http://docs.sequelizejs.com/en/v3/

Using variables in a node.js mysql-node query

I am running a mysql query with WHERE, I would like to include my input prompt variable, input how would I go about doing so? my current query is like so,
var connect = connection.query('SELECT url FROM Sonic_url WHERE name='
+ input //<where I'm confused
, function(err, rows, fields) {
You can just include it the way you did, but that will give you an unescaped query which is open to sql - injection. To prevent you from this, you can use mysql.format
var sql = mysql.format("SELECT url FROM Sonic_url WHERE name=?", [input]);
var connection = connection.query(sql, function(err,rows,fields) {});

Categories