Performance & Security

SQL Injection: How Attacks Work and How to Stop Them

What SQL injection is, how attackers use it, what damage it can do and how to stop it with parameterized queries, input validation, least privilege, safe error handling and regular testing.

Quick answer: SQL injection is an attack where someone sends input that changes the meaning of a database query your application runs. If code builds SQL by gluing user input into a query string, an attacker can read data they should not see, change or delete records, bypass logins and sometimes take over the server. The main fix is simple and well established: use parameterized queries (prepared statements) everywhere, never build SQL with string concatenation, validate input, give the database account only the permissions it needs and hide detailed errors from users.

What SQL injection is

Most websites and applications store data in a relational database such as MySQL, MariaDB, PostgreSQL or SQL Server, and talk to it using SQL. A product page might run a query like “get the product with ID 42”. A login form might run “find the user with this email and password”.

Trouble starts when code builds those queries by inserting user input directly into the SQL text. If the input contains SQL syntax, the database cannot tell the difference between the developer’s instructions and the attacker’s.

Injection has sat at the top of the OWASP Top 10 list of web application risks for years, including the current 2017 edition. Our overview of the OWASP Top 10 puts it in context with other common risks.

A simple example

Imagine a PHP page that looks up a product:

$id = $_GET['id'];
$sql = "SELECT name, price FROM products WHERE id = " . $id;
$result = $db->query($sql);

A normal request uses ?id=42. But an attacker can send something like ?id=42 OR 1=1, and the query becomes:

SELECT name, price FROM products WHERE id = 42 OR 1=1

Now the query returns every product. That alone might seem harmless, but the same technique can join in other tables, such as users and their password hashes, or alter data.

Login forms are another classic target. If a query checks email and password by string concatenation, carefully crafted input can make the condition always true and log the attacker in without a password.

Types of SQL injection

  • In-band (classic): results appear directly on the page, for example extra rows in a listing or data in an error message.
  • Error-based: the attacker uses database error messages to learn about table names and structure.
  • Union-based: the attacker uses UNION to combine results from other tables with the expected query.
  • Blind injection: the page shows no data, but the attacker infers information from true/false differences or response timing.
  • Second-order: malicious input is stored safely at first, then used unsafely later by another part of the application.

Automated tools can find and exploit many of these quickly, which is why injection flaws are often found by bots scanning the web rather than by targeted attackers.

What attackers can do

Depending on the database permissions and the application, a successful attack can:

  • Read customer records, orders, emails and password hashes
  • Change prices, order statuses or account details
  • Create administrator accounts
  • Delete data or whole tables
  • Read files from the server or run commands in some configurations
  • Plant malicious content or links on pages that read from the database

For a business, that means data breach notifications, possible regulatory fines, lost customer trust and expensive cleanup.

How to prevent SQL injection

1. Use parameterized queries everywhere

Parameterized queries (also called prepared statements) send the SQL and the data separately. The database treats input as data only, never as part of the command.

PHP with PDO:

$stmt = $pdo->prepare("SELECT name, price FROM products WHERE id = :id");
$stmt->execute(['id' => $_GET['id']]);
$product = $stmt->fetch();

WordPress with $wpdb:

$product = $wpdb->get_row(
    $wpdb->prepare("SELECT name, price FROM {$wpdb->prefix}products WHERE id = %d", $id)
);

C# with ADO.NET:

var cmd = new SqlCommand("SELECT Name, Price FROM Products WHERE Id = @id", conn);
cmd.Parameters.AddWithValue("@id", id);

This single habit prevents the vast majority of SQL injection flaws.

2. Use ORMs and query builders carefully

Frameworks and ORMs such as Laravel’s Eloquent, Doctrine, Entity Framework and Django’s ORM parameterize queries by default. They still offer raw SQL methods. When developers use raw queries with string concatenation, the protection disappears. Review any raw SQL in your codebase.

3. Handle what cannot be parameterized

Table names, column names and sort directions cannot usually be passed as parameters. If users can choose a sort column, check their choice against an allowlist of permitted column names in code. Never insert those values directly from the request.

4. Validate input

Validation is a second layer, not a replacement for parameterized queries:

  • Cast numeric IDs to integers
  • Check formats for emails, dates and postcodes
  • Enforce length limits
  • Reject unexpected values early

Avoid relying on escaping functions alone. Escaping is easy to get wrong and easy to forget in one place.

5. Apply least privilege

The database user your application connects with should have only the permissions it needs. A public website rarely needs to drop tables or read system tables. Use separate accounts for administration and for the application where possible. This limits damage if a flaw slips through.

6. Hide detailed errors

Detailed database errors help attackers map your database. Show users a generic error page and log the details privately. In PHP, turn off display_errors on production. In ASP.NET, use custom error pages in production.

7. Add a web application firewall

A WAF, such as Cloudflare’s, Sucuri’s or a server-level ModSecurity setup, can block many common injection patterns. It is a useful safety net while you fix code, but not a substitute for secure code. Attackers find ways around generic rules.

8. Keep software updated

On WordPress and other CMS platforms, many SQL injection vulnerabilities come from plugins and themes rather than core. Keep everything updated and remove what you do not use. See our notes on plugin vulnerabilities and WordPress security.

9. Protect APIs too

APIs that accept filters, search terms or IDs are just as exposed as web forms. Apply the same rules to every endpoint. Our guide to API security covers authentication and input handling for APIs.

Testing for SQL injection

  • Code review: search for SQL strings built with concatenation or string interpolation using request data.
  • Automated scanners: tools like OWASP ZAP and sqlmap (used only on systems you own or have permission to test) can find many flaws.
  • Penetration testing: for important applications, a professional test finds issues tools miss, including second-order injection.
  • Logging and monitoring: watch for unusual query errors and suspicious request patterns.

If you think you have been attacked

  1. Take a backup of the current state for investigation
  2. Patch the vulnerable code or disable the affected feature
  3. Check for new admin users, changed content and injected links
  4. Rotate database and admin passwords
  5. Assess what data may have been exposed and follow legal notification requirements
  6. Review logs to understand how and when it happened

Our guide to recovering a hacked WordPress site walks through cleanup in more detail.

FAQ

Is SQL injection still common?

Yes. The fix has been known for many years, but legacy code, rushed custom features and vulnerable plugins keep it alive.

Does using WordPress protect me?

WordPress core uses safe database functions, but plugins and custom code may not. Any custom query should use $wpdb->prepare().

Are stored procedures safe?

Only if they do not build dynamic SQL from input inside the procedure. Parameterize inside procedures too.

Can a firewall alone stop SQL injection?

No. It reduces risk, but secure code is the real fix.

Keep your data where it belongs

SQL injection is old, well understood and still damaging. Parameterized queries, input validation, least privilege and regular testing stop most attacks. If you want your site or application reviewed for injection risks, see how we help you turn visitors into customers on a site your customers can trust.

About the author

Imran M

Leave a Reply

Your email address will not be published. Required fields are marked *

Ready to improve your website?

Let's build a faster, higher performing website.