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!
Subscribe to my newsletter
Read articles from ANURAG SISODIYA directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
ANURAG SISODIYA
ANURAG SISODIYA
I am a software engineer passionate about solving problems, building innovative solutions, and continuously learning in the tech industry. I enjoy exploring new technologies and contributing to the community