SQL Injection (SQLi) is one of the oldest and most damaging web application vulnerabilities. It occurs when untrusted user input is concatenated directly into a database query string, allowing an attacker to manipulate the query execution plan.
A successful SQLi attack can leak user records, bypass authentication screens, modify tables, or execute administrative operations on the underlying server. Let's review the anatomy of an injection vulnerability and how to prevent it.
1. What is SQL Injection?
SQL engines treat query commands (like SELECT or WHERE) and query data (like a username or ID) as parts of a single string. If the application joins them using string interpolation, the engine parses the input as executable code.
For example, consider a login authentication query:
If an attacker inputs admin@devutils.in' OR '1'='1 as the email, the database compiles the query as:
Because '1'='1' is always true, the login validation passes without checking the password, granting the attacker admin access.
2. The Solution: Parameterized Queries (Prepared Statements)
The absolute defense against SQL Injection is separating query instructions from raw data using **Parameterized Queries** (also known as Prepared Statements).
Instead of injecting text directly, you define placeholders (like ? or $1) when writing the SQL structure:
const text = 'SELECT * FROM users WHERE email = $1 AND pass = $2';
const values = [userInput, password];
await pool.query(text, values);
When using prepared statements, the database engine compiles the SQL query template *before* inserting the parameters. The inputs are strictly treated as data values (literals) and can never alter the structure of the database command.
3. Using Object-Relational Mappers (ORMs)
Modern frameworks use ORMs like Prisma, Sequelize, Hibernate, or Entity Framework. By default, ORM methods parameterize inputs automatically:
const user = await prisma.user.findUnique({
where: { email: userInput }
});
However, ORMs are not a silver bullet. If you write raw SQL strings inside ORM escape hatches (like Prisma's $queryRawUnsafe or Sequelize's query), you bypass parameterization and re-introduce injection risks.
4. Summary Checklist for SQL Security
- Never construct SQL query strings by joining raw variables together (string templates, string concatenation).
- Always use parameterized placeholders (
?or$1) for dynamic inputs. - Audit third-party libraries and review raw SQL methods in your ORM layer.
- Restrict database user permissions (Least Privilege) so your app connection cannot run administrative commands like
DROP TABLE.