Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Preventing SQL Injection in Node.js and MySQL Applications

Tech 1

Overview

While it is rare to build backends directly using raw Node.js today, understanding SQL injection attacks is still valuable. This article uses Node.js and MySQL to explain SQL injection vulnerabilities and how to mitigate them.

SQL injection is an ancient attack that has existed since the advant of Web 2.0. It typically occurs in frontend inputs like text boxes and text areas, where attackers inject SQL code into submitted content that gets sent to the backend. If the backend inadvertently concatenates this injected SQL with its own queries, it can execute malicious code. Without proper prevention, this can lead to data leaks, database deletion, and other severe security issues.

SQL Injection Demonstration

Let's use a login flow as an example. First, create a users table in MySQL, then insert a test record:

insert into users (username, password, realname) values ('leihou', '123', '雷猴');

This record has the following fields:

  • username: 'leihou'
  • password: '123'
  • realname: '雷猴'

Next, create a basic vulnerable login endpoint in Node.js:

const mysql = require('mysql');

// Initialize database connection
const dbConnection = mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: '123456',
    port: '3306',
    database: 'testdb'
});

// Establish database connection
dbConnection.connect();

// Universal SQL execution function
function executeSQL(sqlQuery) {
  return new Promise((resolve, reject) => {
    dbConnection.query(sqlQuery, (error, result) => {
      if (error) {
        reject(error);
        return;
      }
      resolve(result);
    });
  });
}

// Vulnerable login function
const vulnerableLogin = (username, password) => {
  const unsafeSql = `
    select username, realname from users where username='${username}' and password='${password}';
  `;

  console.log(unsafeSql);
  return executeSQL(unsafeSql).then(rows => {
    return rows[0] || {};
  });
}

You can use the methods covered in Node.js HTTP Requests to create a public endpoint for frontend access; this article will skip that detail as its not the focus. You can test the endpoint either with a simple HTML page using Ajax, or a tool like Postman.

With valid credentials, the login works as expected:

  • Username: leihou
  • Password: 123

However, an attacker can bypass the password check entirely by inputting leihou' -- (note the spaces before and after the double hyphen) as the username, and entering any random string as the password. The resulting concatenated SQL becomes:

select username, realname from users where username='leihou' -- ' and password='aslkfjsaf';

In MySQL, -- denotes a line comment, so the query effectively only filters for users with username leihou, completely ignoring the password check.

Worse, an attacker could delete your entire users table by inputting leihou'; delete from users; -- as the username, which would execute the delete command after the original query.

Prevention Methods

SQL injection has been a known threat for over a decade, so standard mitigation techniques are well-established. One core approach is to escape special characters in user-supplied input.

The official MySQL npm package for Node.js includes an escape method that handles this sanitization automatically. Here is the fixed, secure login function:

const mysql = require('mysql');

// Initialize connection and executeSQL function as shown earlier
const escapeInput = mysql.escape;

const secureLogin = (username, password) => {
  const escapedUsername = escapeInput(username);
  const escapedPassword = escapeInput(password);
  const safeSql = `
    select username, realname from users where username=${escapedUsername} and password=${escapedPassword};
  `;

  console.log(safeSql);
  return executeSQL(safeSql).then(rows => {
    return rows[0] || {};
  });
}

When an attacker inputs leihou' -- as the username, the escaped SQL logged to the console will be:

select username, realname from users where username='leihou\' -- ' and password='123345';

The single quote in the input is properly escaped, preventing the comment injection attack.

Recommended Reading

  • Node.js HTTP Requests
  • Node.js 5-Minute Guide to Connecting MySQL for CRUD Operations
  • Node.js Stream Basics
  • Node.js Working with Cookies
  • Node.js 5-Minute Guide to Connecting Redis for Read/Write Operations
  • *Node.js Reading and Writing Files'
Tags: Node.jsMySQL

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.