SQL Injection and Security — Protecting Your Database from Malicious Input
Prevent SQL Injection
A school search form accepts a city. Directly inserting its text into a query can allow that text to change the intended condition.
SQL injection occurs when untrusted input is interpreted as part of a statement’s structure. Parameter binding keeps ordinary input values separate from SQL syntax.
Explain and apply
Bind a user-supplied value and explain why it must not become part of the SQL command.
Work it out
Bind the city value Pune to a fixed statement. Explain what happens if the supplied value contains quote characters.
Avoid mistakes
Escaping and filtering alone are fragile substitutes for binding.
Prevent SQL Injection: the request and its result
School need
A school search form accepts a city. Directly inserting its text into a query can allow that text to change the intended condition.
Database operation
SQL injection occurs when untrusted input is interpreted as part of a statement’s structure. Parameter binding keeps ordinary input values separate from SQL syntax.
Check the outcome
The parameter is a city value, not SQL grammar. A value containing a quote remains data instead of introducing a new OR condition. The Python and Java examples show their drivers’ actual binding APIs.
Understand what the database does
Write a fixed statement with the driver’s parameter placeholders, then supply the values through its binding API. Keep dynamic identifiers on an explicit allowlist. Validate business rules separately and use an account whose permissions match the application’s actual tasks.
Related concepts: Dynamic SQL and SQL with Python and SQL with Java.
What is SQL Injection?
SQL Injection is a code injection technique where malicious SQL is inserted into a query via user input. If not properly handled, it can manipulate or expose your entire database.
Basic Scenario – Unsafe Query
SQL · portable concepts; preserved examples identify their engine
Let’s assume a school has a student login system:
SELECT * FROM students
WHERE roll_no = '3' AND password = 'pass123';
This query is generated using user input, like this:
// Pseudo-code (not actual SQL)
"SELECT * FROM students WHERE roll_no = '" + input_roll + "' AND password = '" + input_pass + "'";
SQL Injection in Action
SQL · portable concepts; preserved examples identify their engine
Now imagine this input:
input_roll: 3
input_pass: ' OR '1'='1
The final query becomes:
SELECT * FROM students
WHERE roll_no = '3' AND password = '' OR '1'='1';
Result: The condition always returns true, and the attacker logs in without a valid password.
Advanced Injection – DROP TABLE
SQL · portable concepts; preserved examples identify their engine
input_roll: 3
input_pass: pass123'; DROP TABLE students; --
Final SQL:
SELECT * FROM students WHERE roll_no = '3' AND password = 'pass123';
DROP TABLE students;
--'
This deletes the entire students table. Terrifying, right?
How to Prevent SQL Injection
SQL · portable concepts; preserved examples identify their engine
1. Use Prepared Statements (Parameterized Queries)
This is the most effective solution. It separates data from SQL logic.
// In MySQL or PHP using PDO:
$stmt = $conn->prepare("SELECT * FROM students WHERE roll_no = ? AND password = ?");
$stmt->bind_param("is", $roll_no, $password);
$stmt->execute();
2. Validate and Sanitize Input
- Use input types like
numberoremail - Check length, pattern, and format of input
3. Escape Dangerous Characters
Escape quotes, semicolons, and dashes in input (only when using dynamic SQL — not recommended).
4. Use ORM or Query Builders
Frameworks like Django, Laravel, or Hibernate handle queries securely behind the scenes.
5. Least Privilege Access
The database user used by the app should not have DROP or ALTER rights.
Secure Example with Prepared Statement
SQL · portable concepts; preserved examples identify their engine
// PHP + MySQLi example
$stmt = $conn->prepare("SELECT name FROM students WHERE roll_no = ? AND password = ?");
$stmt->bind_param("is", $roll_no, $password);
$stmt->execute();
Even if someone tries to inject malicious SQL, it will be treated as plain input — not executable code.
Real-World School Use Cases
- Prevent fake login during parent-teacher meetings
- Secure marks upload pages used by staff
- Protect student registration forms from malicious bots
Best Practices Checklist
Query discussed in this section:
// PHP + MySQLi example
$stmt = $conn->prepare("SELECT name FROM students WHERE roll_no = ? AND password = ?");
$stmt->bind_param("is", $roll_no, $password);
$stmt->execute();
- Always use prepared statements
- Validate all user inputs
- Never concatenate user input into raw SQL
- Limit DB user privileges
- Use security-aware frameworks
Important differences and mistakes
Escaping and filtering alone are fragile substitutes for binding. A prepared statement does not make every concatenated identifier safe. An ORM can still execute unsafe raw SQL, and least privilege reduces potential damage without fixing an injected query.
Try it with the school data
Bind the city value Pune to a fixed statement. Explain what happens if the supplied value contains quote characters.
This practice uses a separate, fresh fixture named practice_students. It does not continue the changing table state of the earlier examples.
| roll_no | name | class | marks | city |
|---|---|---|---|---|
| 1 | Aarav | 10A | 85 | Pune |
| 2 | Diya | 9B | 70 | Chennai |
| 3 | Sneha | 10A | 85 | Pune |
SQL · create only these practice tables in a disposable database:
CREATE TABLE practice_students (roll_no INTEGER PRIMARY KEY, name VARCHAR(50), class VARCHAR(10), marks INTEGER, city VARCHAR(30));
INSERT INTO practice_students VALUES
(1, 'Aarav', '10A', 85, 'Pune'),
(2, 'Diya', '9B', 70, 'Chennai'),
(3, 'Sneha', '10A', 85, 'Pune');
Worked answer and reasoning
This practice uses a separate, fresh fixture named practice_students. It does not continue the changing table state of the earlier examples.
| roll_no | name | class | marks | city |
|---|---|---|---|---|
| 1 | Aarav | 10A | 85 | Pune |
| 2 | Diya | 9B | 70 | Chennai |
| 3 | Sneha | 10A | 85 | Pune |
SQL · create only these practice tables in a disposable database:
CREATE TABLE practice_students (roll_no INTEGER PRIMARY KEY, name VARCHAR(50), class VARCHAR(10), marks INTEGER, city VARCHAR(30));
INSERT INTO practice_students VALUES
(1, 'Aarav', '10A', 85, 'Pune'),
(2, 'Diya', '9B', 70, 'Chennai'),
(3, 'Sneha', '10A', 85, 'Pune');
SQL · this practice variation runs with SQLite 3; the preserved examples retain their stated dialect
Bind the value "Pune" through the driver’s parameter API. The question mark is a parameter marker, not literal SQL text to replace with string concatenation.
SELECT name FROM practice_students WHERE city = ? ORDER BY roll_no;| name |
|---|
| Aarav |
| Sneha |
The parameter is a city value, not SQL grammar. A value containing a quote remains data instead of introducing a new OR condition. The Python and Java examples show their drivers’ actual binding APIs.
Check your understanding
Check your understanding
Use the idea independently
SQL injection occurs when untrusted input is interpreted as part of a statement’s structure. Parameter binding keeps ordinary input values separate from SQL syntax.
The parameter is a city value, not SQL grammar. A value containing a quote remains data instead of introducing a new OR condition. The Python and Java examples show their drivers’ actual binding APIs.
Continue your understanding with Dynamic SQL and SQL with Python and SQL with Java.
Source for the engine-specific behavior: MySQL 8.4 reference documentation.
Reaching the recap and completing the quizzes are separate milestones.