Articles on: Troubleshooting
This article is also available in:

SQL injection: What is it and how can you protect yourself?

What is SQL Injection?


SQL Injection (SQLi) remains at the top of the most dangerous web vulnerabilities for a simple reason: it is easy to exploit and devastating to the business. The attack happens when the application accepts user data and, instead of treating it strictly as information, ends up concatenating it directly into the SQL query string. As a result, the database interprets the malicious text as if it were a command from the system itself.


If your system joins variables from forms or URLs directly into the query, you have basically opened the door for anyone to access, modify, or delete your sensitive data.


The Attack in Real Life


Looking at a common authentication system, the application receives the entered email and builds the search query. If an attacker fills the email field with the following value:


'admin@example.com' OR '1'='1'


The query processed by the server will look like this:


SELECT * FROM usuarios WHERE email = 'admin@example.com' OR '1'='1' AND senha = '...';


Because the condition '1'='1' is always true, the database ignores the rest of the validation. The attacker successfully bypasses the password check and gains direct access to the administrator account.


How to Protect Your Code Step by Step


The golden rule of secure development is universal: never trust user input. Below, see how to apply the main defenses using Node.js and Python.


Parameterized Queries (Prepared Statements)


This is the most important line of defense. Instead of building dynamic strings, you define the query structure first and pass the user data as isolated arguments. The database driver ensures that these parameters are treated strictly as literal values, neutralizing any hidden commands.


Example in JavaScript (Node.js + pg package)


// THE WRONG WAY: Dangerous concatenation
const query = `SELECT * FROM usuarios WHERE email = '${req.body.email}'`;
const result = await pool.query(query);

// THE RIGHT WAY: The driver isolates the content of $1
const query = 'SELECT * FROM usuarios WHERE email = $1';
const values = [req.body.email];
const result = await pool.query(query, values);


Example in Python (psycopg2 driver)


# THE WRONG WAY: String formatting generates the query before sending it
query = f"SELECT * FROM usuarios WHERE email = '{user_input}'"
cursor.execute(query)

# THE RIGHT WAY: Data is sent separately from the query structure
query = "SELECT * FROM usuarios WHERE email = %s"
cursor.execute(query, (user_input,))


Note: Even though Python uses %s or ? in the query text, this is not standard string interpolation. The driver sends the command and the parameters over separate channels to the database.


Input Validation and Sanitization


Stopping the problem before it even gets close to the database saves processing power and increases security. Ensure that the received data matches the format expected by the application.


Validation in Node.js

// Forcing conversion to guarantee an integer in the route
const userId = parseInt(req.params.id, 10);

if (isNaN(userId)) {
return res.status(400).json({ error: "Invalid ID." });
}


Validation in Python

import re

# Checking the email format with a regular expression before using it in the search
email_pattern = r"^[\w\.-]+@[\w\.-]+\.\w+$"

if not re.match(email_pattern, user_input):
raise ValueError("Invalid email format.")


Up-to-Date ORM Ecosystem


Modern ORM tools handle parameterization natively under the hood for most calls.


  • In the JS ecosystem (Sequelize, Prisma): Structured queries via User.findOne({ where: { email } }) are secure by design.
  • In the Python ecosystem (SQLAlchemy, Django ORM): Methods like User.objects.filter(email=user_input) block SQLi automatically.


Be careful if you need to write raw SQL queries within these frameworks. Functions like db.execute("SELECT...") lose automatic protection and require manual parameterization identical to the previous examples.


Replacing string concatenation with parameterized queries resolves the vast majority of SQL Injection risks. Combining this practice with rigorous validation of received payloads shields your ecosystem and ensures application data integrity.

Updated on: 06/30/2026

Was this article helpful?

Share your feedback

Cancel

Thank you!