How SQL Injection Works
SQL injection (SQLi) involves inserting malicious SQL (Structured Query Language — database query language) commands into unfiltered user input. When an application directly concatenates this input into a query, the database executes the attacker's code as if it were part of the legitimate query.
Classic example: a vulnerable login form. The attacker enters ' OR '1'='1 as the password. The query becomes:
SELECT * FROM users WHERE username='admin' AND password='' OR '1'='1'
The condition '1'='1' is always true, granting access without a valid password.
Types of SQL Injection
Classic In-Band: the result of the injection is directly visible in the HTTP response — revealing SQL error messages or extracted data displayed on the page.
Blind-Boolean: the application doesn't return data but changes behavior based on whether an injected condition is true or false. The attacker deduces data bit by bit by asking binary questions.
Time-Based Blind: no visible difference in the response, but the attacker injects delay functions (SLEEP(5) in MySQL) to infer information from the server's response time.
Out-of-Band: the attacker exfiltrates data via a secondary channel (DNS or HTTP request from the database server). Requires specific permissions.
Consequences of a Successful Injection
- Reading the entire database: credentials, passwords, personal data.
- Complete authentication bypass.
- Modification or deletion of data.
- On SQL Server: execution of system commands via
xp_cmdshell, compromising the entire server.
Prepared Statements: The Primary Solution
Prepared statements with bound parameters separate SQL code from data. The database first compiles the query, then receives the parameters separately. Even if a parameter contains SQL, it is treated as a string, never as code.
# Vulnerable
query = "SELECT * FROM users WHERE email = '" + email + "'"
# Secure (bound parameter)
cursor.execute("SELECT * FROM users WHERE email = %s", (email,))
ORMs (Object-Relational Mapping — object-relational abstraction layer) such as Django ORM, SQLAlchemy, or Hibernate automatically generate prepared statements. They drastically reduce injection risk as long as raw unparameterized queries are avoided.
Complementary Defenses
Principle of least privilege: the database user used by the application should have only the strictly necessary rights (SELECT, INSERT) — never DROP, CREATE, or access to system tables.
WAF (Web Application Firewall): filters known malicious requests upstream, but does not replace prepared statements. It is a defense-in-depth measure.
The open source tool sqlmap allows you to automatically test your endpoints (API access points or forms) to detect SQL injections before an attacker does.
Check Your Site's Security
A security audit identifies risky configurations, missing headers, and development practices that expose your databases. Run a free audit to assess your site's resistance to SQL injection and other common attacks.