What is SQL Injection and how to prevent it?
SQL injection is a type of web application vulnerability that allows an attacker to execute arbitrary SQL code on a database. This can be used to steal sensitive data, modify or delete data, or even take control of the entire system.
Example
Here's an example of how SQL injection can be used to bypass authentication and gain access to a system:
Suppose you have a web application that allows users to log in with a username and password. The application uses the following SQL query to check if the user's credentials are valid:
SELECT * FROM users WHERE username = '<username>' AND password = '<password>'
The <username>
and <password>
parameters are supplied by the user via a web form. An attacker can exploit this by entering a malicious username or password that includes SQL code, such as:
' OR 1=1 --
This will cause the SQL query to become:
SELECT * FROM users WHERE username = '' OR 1=1 --' AND password = '<password>'
The --
symbol is used to comment out the rest of the SQL query, effectively bypassing the password check and returning all rows from the users
table.
How to Prevent?
Parameterized Queries
To prevent SQL injection, you should always use parameterized queries or prepared statements. These are a way of separating the SQL code from the user-supplied data, ensuring that the data is treated as data and not as part of the SQL code. Here's an example of how to use parameterized queries in Node.js with the pg
module:
const { Client } = require('pg');
// Set up a client to connect to the PostgreSQL database
const client = new Client({
host: 'your-database-host',
port: 5432,
user: 'your-database-user',
password: 'your-database-password',
database: 'your-database-name',
});
// Define a function to validate user credentials using parameterized queries
async function validateUser(username, password) {
const query = 'SELECT * FROM users WHERE username = $1 AND password = $2';
const values = [username, password];
const result = await client.query(query, values);
return result.rows[0];
}
// Call the validateUser function with user-supplied data
validateUser(req.body.username, req.body.password).then((user) => {
if (user) {
// Log the user in
} else {
// Show an error message
}
}).catch((err) => {
console.error(err);
});
In the example above, we define a validateUser
function that uses parameterized queries to check if the user's credentials are valid. The function takes two arguments, username
and password
, which are supplied by the user via a web form. The query
parameter contains the SQL code, with placeholders $1
and $2
for the username
and password
values. The values
parameter is an array that contains the actual values to be substituted for the placeholders. Finally, the client.query
method is used to execute the query with the user-supplied data.
By using parameterized queries, you can prevent SQL injection and ensure that user-supplied data is always treated as data, rather than as part of the SQL code.
Sanitize User Input
Even when using parameterized queries, it's still important to sanitize user input to prevent any unexpected behavior. This includes stripping out any unwanted characters, such as single quotes or semicolons, that could be used to inject SQL code.
Here's an example of how to sanitize user input in Node.js:
function sanitizeInput(input) {
return input.replace(/[^a-z0-9]/gi, '');
}
const username = sanitizeInput(req.body.username);
In the example above, we define a sanitizeInput
function that removes any non-alphanumeric characters from user input. The username
variable is then sanitized before being used in a SQL query.
Use Least Privilege Principle
It's important to follow the least privilege principle, which means giving users or applications only the minimum level of access required to perform their tasks. This can help limit the potential impact of any SQL injection attacks by restricting the attacker's ability to modify or access sensitive data.
Keep Software Up-to-Date
It's important to keep your database management software, as well as any dependencies and libraries, up-to-date to ensure that any known vulnerabilities or bugs are patched.
Subscribe to my newsletter
Read articles from Harsh Mange directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Harsh Mange
Harsh Mange
This is Harsh Mange, working as a Software Engineer - Backend at Argoid. I love building apps. Working on contributing to open-source projects and the dev community.