Protecting Against SQL Injection
# CHAPTER 10
Protecting Against SQL Injection
1. Introduction
For over two decades, SQL Injection (SQLi) has consistently ranked as one of the most dangerous and prevalent vulnerabilities on the internet. If your API connects to a relational database (like MySQL) and handles user input incorrectly, an attacker can hijack your database queries. They can bypass logins, steal all customer data, or simply delete the entire database. In this chapter, we will dissect how SQL Injection works and learn the absolute, foolproof method to prevent it in PHP: Prepared Statements using PDO.2. Learning Objectives
By the end of this chapter, you will be able to:- Explain the mechanics of a SQL Injection attack.
- Understand how string concatenation causes SQL vulnerabilities.
- Identify the catastrophic consequences of a successful SQLi attack.
- Refactor vulnerable PHP/MySQLi code into secure code.
- Implement PHP Data Objects (PDO) Prepared Statements.
3. Beginner-Friendly Explanation
Imagine you are filling out a bank deposit slip. The slip is pre-printed with: "Deposit $_____ into account #12345". You write "100" in the blank space. The teller reads it and executes: "Deposit $100 into account #12345".A SQL Injection is when you write malicious instructions in the blank space.
Instead of "100", you write: "100. Actually, never mind, give me all the cash in the vault instead."
If the teller is a dumb computer program (a vulnerable API), it reads the whole sentence as a valid instruction, ignores the original deposit plan, and hands you all the cash in the vault.
To stop this, we use Prepared Statements. This forces the teller to treat whatever you wrote strictly as a *value* (a number or a name), and absolutely never as an *instruction*.
4. Real-World Attack Scenarios
-
The Authentication Bypass: An API login endpoint expects a username. An attacker sends
' OR '1'='1. The resulting SQL query becomesSELECT * FROM users WHERE username = '' OR '1'='1'. Since 1 always equals 1, the database returns the first user in the table (usually the Admin) without requiring a password!
-
Data Exfiltration (UNION-Based): An attacker injects a
UNION SELECTstatement into a search API. The API is supposed to return products, but the injected query forces the database to append the contents of thepasswordstable to the product results.
5. Vulnerable Code Example (String Concatenation)
This is the classic mistake that causes SQL Injection. Do NOT do this.The attacker just terminated the first query with a semicolon ;, and executed a second query that deletes the entire user table.
6. Secure Code Example (PDO Prepared Statements)
The universal solution to SQL Injection is separating the SQL code from the user's data.Using PDO (PHP Data Objects):
If the attacker sends admin'; DROP TABLE users, the database literally searches for a user whose actual name is "admin'; DROP TABLE users". It finds nothing, and the attack fails harmlessly.
7. Named Placeholders
If you have a query with many variables, using? can get confusing. PDO supports named placeholders, which are highly recommended for readability.
8. What about mysqli_real_escape_string()?
In old PHP tutorials (pre-2015), you will see developers "escaping" data before putting it into a query to prevent SQL injection.
*Do not use this method for new projects.* Escaping strings is prone to human error; if a developer forgets to escape just one variable in a massive query, the API is compromised. Prepared statements are fundamentally safer and faster.
9. Best Practices
- Use PDO Exclusively: Adopt PDO for all database interactions in PHP. It supports 12 different database types and enforces prepared statements cleanly.
-
Never Concatenate: Make it a strict rule in your codebase: Never use the
.operator or variable interpolation (e.g.,"SELECT * FROM users WHERE id = $id") to insert variables into a SQL string.
- Least Privilege Database User: The MySQL user account your API uses should only have permission to execute DML (Select, Insert, Update, Delete). It should NEVER have permission to DROP tables or alter schema.
10. Common Mistakes
-
Prepared Statements on Table/Column Names: You *cannot* use placeholders (
?) for Table names or Column names.SELECT * FROM ? WHERE ? = ?will crash. Placeholders are ONLY for values. If you must dynamically sort by a column name, you must strictly Allow-list the column name in PHP before inserting it into the query.
- Using Unprepared Queries for "Safe" Data: Developers sometimes skip prepared statements if the data comes from a trusted source (like an internal API or a cookie). Never assume data is safe. Use prepared statements for *everything*.
11. Mini Exercises
- 1. What character is used as an unnamed placeholder in a PDO prepared statement?
-
2.
Explain why a hacker injecting
' OR '1'='1bypasses a poorly written login query.
12. Practice Challenges
Challenge: Review the following vulnerable code:Rewrite this code using PDO Prepared statements and named placeholders to make it secure against SQL injection.
13. MCQs with Answers
What is the root cause of a SQL Injection vulnerability?
What is the industry-standard method to completely prevent SQL Injection in modern web applications?
If an attacker inputs admin'; DROP TABLE users; -- into a login form, and the backend uses proper Prepared Statements, what will happen?
14. Interview Questions
- Q: Explain how a SQL Injection attack works, providing an example of an Authentication Bypass payload.
- Q: Exactly how do Prepared Statements (Parameterized Queries) neutralize SQL Injection? Why are they better than escaping strings?
-
Q: Can you use a PDO placeholder (
?) for a database table name? If not, how do you securely handle dynamic table selection?
15. FAQs
Q: Do NoSQL databases (like MongoDB) suffer from SQL Injection? A: They don't suffer from traditional SQLi, but they do suffer from "NoSQL Injection". If you pass raw JSON objects from the client directly into a MongoDB query, an attacker can manipulate query operators (like$ne for "not equal") to bypass authentication. Prepared statements/parameterization concepts still apply!