SQL Injection Prevention: Parameterized Queries, Safe Dynamic SQL, and Least Privilege
SQL injection happens when untrusted input is mixed into SQL as code instead of data. The strongest fix is not filtering suspicious characters—it is preventing input from changing the query structure.
Use Parameterized Queries
Unsafe:
const sql = `SELECT id, email FROM users WHERE email = '${email}'`;
Safe pattern:
const sql = 'SELECT id, email FROM users WHERE email = ?';
const [rows] = await db.execute(sql, [email]);
Prepared/parameterized queries define the SQL structure separately from values, so user input remains data. OWASP lists this as the primary defense.
ORMs Are Not Automatically Safe
ORM query builders are useful when they bind parameters correctly. Risk returns when developers use raw SQL APIs and concatenate strings manually.
Review every escape hatch such as:
rawQuery()
queryRaw()
executeRaw()
native SQL
according to the framework's parameter-binding API.
Dynamic SQL Needs Allowlists
Some SQL elements—such as table names, column names, or sort direction—cannot always be supplied as normal bind parameters.
Do not concatenate arbitrary input. Map user choices to known-safe values:
const sortColumns = {
newest: 'created_at',
amount: 'total_amount'
};
const column = sortColumns[input] ?? 'created_at';
The application chooses the SQL identifier; the user only chooses from an allowlisted option.
Stored Procedures Are Not Magic
Stored procedures can be safe when values are parameterized. They can still become injectable if they build dynamic SQL through unsafe string concatenation.
They can also increase blast radius if the application must receive unnecessarily powerful database roles just to execute them.
Do Not Rely on Escaping as the Main Defense
OWASP strongly discourages trying to escape every user-supplied value as the primary SQL-injection defense. Escaping is database-specific and fragile compared with parameterization.
Input validation remains useful for business correctness, but it does not replace bind parameters.
Limit Database Privileges
Run the application using the minimum permissions it needs. A read-only reporting service should not have DROP, schema administration, or unrelated table privileges.
Least privilege cannot prevent an injection bug, but it can reduce the damage if one exists.
Final Takeaway
SQL injection prevention is mostly one rule: never build executable SQL structure from untrusted strings. Parameterize values, allowlist unavoidable dynamic identifiers, review ORM raw-query paths, and keep database privileges narrow.
References
BUILDING A SAAS PRODUCT?
Explore Lofingo’s end-to-end SaaS platforms, multi-tenant cloud architecture, and high-concurrency backend engineering.
EXPLORE SAAS SERVICES →