SQL Injection Prevention
SQL injection lets an attacker rewrite your query by typing into a form. It is still one of the most damaging web vulnerabilities — and completely preventable.
On this page · 5 min · Intermediate
On this page
- In simple words
- Learning objectives
- Explanation
- Code example
- Step by step
- Real-world use
- Common mistakes
- Best practices
- Remember this
- Practice exercise
- Mini quiz
- Related topics
- My notes
- Reading time
- 5 min
- Difficulty
- Intermediate
- Updated
- Oct 29, 2026
Related tutorials
In simple words#
SQL injection is someone writing extra instructions inside a form box (“…and give me all passwords”). Parameters treat whatever they write as plain text, never as instructions.
- SQL injection
- Attacker input changes your SQL.
- Fix
- Parameters for every value.
- Whitelist
- For column names you cannot parameterise.
Learning objectives#
- See how injection happens
- Fix it with parameters
- Handle dynamic sort columns safely
- Add defence in depth
Explanation#
Injection happens when user input is concatenated into SQL text. Input such as ' OR '1'='1 changes the meaning of the query.
Parameters fix it completely for values, because values are never parsed as SQL.
Table names, column names and sort directions cannot be parameters. Map user choices to a fixed whitelist instead.
Stored procedures are safe only if they do not build dynamic SQL from their inputs. Use sp_executesql with parameters if they must.
Defence in depth: the app’s login should have only the permissions it needs — never sysadmin or db_owner.
Code example: Vulnerable vs safe#
// ❌ VULNERABLE: input "x' OR '1'='1" logs in as the first user
var bad = quot;SELECT Id FROM Users WHERE Email = '{email}' AND PasswordHash = '{hash}'";
// ✅ SAFE: values are parameters
await using var cmd = new SqlCommand("SELECT Id FROM Users WHERE Email = @email", conn);
cmd.Parameters.Add("@email", SqlDbType.NVarChar, 256).Value = email;
// ✅ SAFE dynamic ORDER BY: whitelist, never raw input
string orderBy = sort switch
{
"price" => "Price",
"name" => "Name",
_ => "Id",
};
string dir = descending ? "DESC" : "ASC";
var listSql = quot;SELECT Id, Name, Price FROM Products ORDER BY {orderBy} {dir}";
The vulnerable query returns a user for any password. The safe versions treat input only as data, and ORDER BY can only ever be one of three known columns.
This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.
Step-by-step explanation#
- String interpolation puts attacker text directly into the SQL.
- The parameterised query compares Email with the input as a value.
- The switch maps user input to known column names; anything else falls back to Id.
- Verify the password hash in C# with a proper hashing library, not in SQL text.
Real-world use case#
A security review greps the codebase for "SqlCommand(" with
quot; or + and fixes every match — a quick win before a penetration test.Common mistakes#
Replace("'", "''") misses edge cases and encodings. Use parameters.
Attackers send any request they like. Treat all input as untrusted.
Best practices#
- Parameters for every value
- Whitelist identifiers
- Least-privilege database logins
- Code review and static analysis for concatenated SQL
Remember this#
Never concatenate input into SQL.
Values → parameters. Names → whitelist.
App login ≠ db_owner.
Practice exercise#
Your task: Fix this code: new SqlCommand("DELETE FROM Products WHERE Id = " + id, conn).
Show solution
await using var cmd = new SqlCommand("DELETE FROM Products WHERE Id = @id", conn);
cmd.Parameters.Add("@id", SqlDbType.Int).Value = id;
Mini quiz#
How should a user-chosen sort column be handled?
Want more? Practise all ADO.NET MCQs · ADO.NET interview questions
My notes#
Saved in this browser.