How to Protect Your Codebase from SQL Injection Attacks

How to Protect Your Codebase from SQL Injection Attacks

Introduction

SQL injection is one of the most common and dangerous vulnerabilities in web applications. It occurs when attackers can manipulate SQL queries through user input, potentially gaining unauthorized access to your database or even executing harmful operations. In this blog, we’ll explore what SQL injection is, how it works, and most importantly, how to prevent it using parameterized queries.

The Problem: Vulnerable Code

Let’s look at an example where user input is directly injected into an SQL query. Here's a basic (but vulnerable) code snippet:

username = input("Enter your username: ")
password = input("Enter your password: ")

query = f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}'"
cursor.execute(query)

At first glance, this might seem like a normal way to fetch data from a database based on user input. However, by directly inserting user-provided values into the query string, you're exposing your application to SQL injection attacks.

How an Attacker Exploits This

Let’s see how an attacker could manipulate this query using malicious input.

For a normal user, the inputs might be:

  • username = alice

  • password = secret

This results in the following SQL query:

SELECT * FROM users WHERE username = 'alice' AND password = 'secret';

But an attacker could enter:

  • username = ' OR 1=1 --

  • password = anything

Which results in this SQL query:

SELECT * FROM users WHERE username = '' OR 1=1 --' AND password = 'anything';

The part OR 1=1 always evaluates to TRUE, so the query returns all users, potentially bypassing the password check. The -- comment symbol makes the database ignore the rest of the query, including the password condition, giving the attacker unauthorized access

The Solution: Parameterized Queries

The best way to prevent SQL injection is by using parameterized queries. These ensure that user input is treated as data, not executable code. Let’s rewrite the vulnerable code with this technique:

username = input("Enter your username: ")
password = input("Enter your password: ")

query = "SELECT * FROM users WHERE username = %s AND password = %s"
cursor.execute(query, (username, password))

By using placeholders (%s in this case) and passing the user input separately, the database automatically escapes any special characters. This makes it impossible for attackers to alter the query’s structure.

secure execution in action

Even if the attacker tries to input:

  • username = ' OR 1=1 --

  • password = anything

The query becomes:

SELECT * FROM users WHERE username = '\ OR 1=1 --' AND password = 'anything';

The backslash (\) escapes the special characters, ensuring that the input is treated as a literal string, not executable SQL. This process is handled internally by the database driver, which is why parameterized queries are so effective at preventing SQL injection.

Other Best Practices to Prevent SQL Injection

  • Input Validation: Always validate and sanitize user input to ensure it meets your expected criteria (e.g., string length, allowed characters).

  • Use ORM Libraries: Object-Relational Mapping (ORM) libraries like SQLAlchemy (Python), Hibernate (Java), or ActiveRecord (Ruby on Rails) help abstract raw SQL queries, making it easier to avoid SQL injection.

  • Least Privilege Principle: Ensure that your database user accounts have only the minimum permissions required. For example, a read-only account should be used where applicable to limit the impact of an attack.

  • Prepared Statements: In addition to parameterized queries, use prepared statements where possible. These precompile your SQL queries, making them even more resistant to injection

Conclusion

SQL injection remains a critical security risk, but it is entirely preventable with proper coding practices. By using parameterized queries, you can protect your application from attackers and keep your database secure.

Don't wait until it’s too late—secure your SQL queries today!