Blind SQL Injection: what it is and how to prevent it
In this blog, we’ll start with the basics and then move on to a more advanced variant that is often overlooked: Blind SQL injection.
Injection has been listed as a major security risk for web applications in the OWASP Top 10 for many years. There are multiple forms of injection, but SQL injection remains one of the most common ways to compromise an application.What makes this particularly notable is that SQL injection is relatively easy to prevent, yet it continues to appear in real-world applications.
OWASP Top 10
The Open Web Application Security Project (OWASP) is a non-profit organization focused on improving the security of web applications. In addition to various open source projects and conferences, OWASP maintains the well-known Top 10.
This list highlights the most critical security risks, along with examples and mitigation strategies to help developers secure their applications. Injection, and SQL injection in particular, has been near the top of this list for years. Every developer should be familiar with this risk, yet it still goes wrong in practice.
I previously wrote a blog about the most recent OWASP Top 10 (2025), which you can read here.
Before diving into Blind SQL injection, let’s first take a quick look at SQL injection itself.
SQL Injection in short
Web applications almost always use a database to store and retrieve data. The application sends queries to the database, often based on user input. For example:
- Opening an article on a news site
- Searching for products in a webshop
- Logging in with a username and password
These queries often include user input. With SQL injection, an attacker manipulates that input to execute additional SQL code.
Take the following example:
string query = "SELECT [name] FROM product WHERE Listprice > " + searchPrice + " ORDER BY [name]";
This works fine if a user enters “200”. But what happens with:
200 or 1=1
The resulting query becomes:
“SELECT [name] FROM product WHERE Listprice > 200 or 1=1 ORDER BY [name]”
The WHERE clause checks each record in the database to determine whether it satisfies the condition after “WHERE”. Since 1=1 is always true, all records will be returned. In this case, that may not seem like a big issue, as all products are simply displayed. However, in a login scenario, this becomes much more problematic.
Consider the query below. If a developer does not account for SQL injection, the code might look like this.
string query = "SELECT Top(1) * FROM users WHERE username = '" + username + "' and password = '" + password + "'";

By ending the input with --, everything that follows is treated as a comment and ignored by the database. This effectively removes the password check.
The 1=1 condition makes the query always evaluate to true, meaning any user matches. The database will then return the first user, which is often an administrator.
More examples
Using UNION, it is also possible to retrieve data from other tables or query information about the database itself. For example, you could determine which tables exist in the database.
Let’s apply this to the earlier example, where we search for products based on price:
10000 union select [name] from sys.tables –

This input returns an overview of all tables in the database.
Reading data, however, is only part of the problem. SQL injection can also be used to perform mutations such as UPDATE, INSERT, and DELETE.
0; update product set [ListPrice] = 0 where [name] = 'Laptop' --
In this scenario, the price of a product is set to 0. This could allow someone to purchase it for free and then restore the original price afterward.
What is Blind SQL Injection?
Unintended updates, inserts, and deletes can be problematic, but the greatest risk usually arises when sensitive data is exposed. Modified or deleted data can often be restored from backups, but once data has been leaked, it cannot be recovered.
That is why SQL injection defenses often focus on SELECT queries, as they can directly retrieve data. UPDATE statements only modify data and do not return any results in the application’s response.
At first glance, it may seem that injecting into an update statement does not provide any useful information to an attacker.
In practice, however, this is not the case. Even without direct output, it is still possible to extract information from the database. This is known as Blind SQL injection.
Even though an attacker cannot directly see the database output (hence “blind”), they can still infer information. This is often done by influencing the behavior of the application, for example by manipulating response times.
As an example, consider the following update statement:
UPDATE Product SET name = name WHERE ProductID = 1
Where the value “1” is derived from user input.
An attacker could replace this value with something like the following:
1; IF (SELECT 1 FROM Person WHERE Lastname = 'Peeters' AND SUBSTRING(FirstName, 1, 1) = 'A') = 1 WAITFOR DELAY '0:0:5'
If the first letter of the first name is “A”, the response will be delayed by 5 seconds. If the response remains fast, the condition is not met.

In this case, the query completes almost immediately (in less than a second), so the first letter is not “A”. By repeating this process and testing a different letter each time, an attacker can gradually determine the correct value. In practice, this is usually automated.
If you were to do this manually, you would soon notice that, for example, the letter “C” does trigger a 5-second delay. That tells you that this is the correct letter.

You then repeat this process for the next character. While time-consuming, it is still possible to extract data this way.
Blind SQL injection comes in multiple forms, but the principle is the same: data is not retrieved directly, but inferred through true/false conditions.
Besides time-based techniques, attackers may also rely on error-based methods by deliberately triggering database errors.

Using these techniques, an attacker can determine, for example:
- Whether a table “users” exists
- Whether a column “username” exists
- Whether a user “admin” exists
- Whether a column “creditcard” exists
- And so on
This example is based on Microsoft SQL Server, but similar techniques can be used with other databases. For example, MySQL provides a SLEEP() function, and PostgreSQL offers pg_sleep().
How to prevent SQL injection?
The key question: how do you prevent SQL injection?
The basic rule is simple: never trust user input. Not just in SQL queries, but in any situation where input from the client is used. This includes not only form fields, but also URL parameters, API calls, and JSON payloads.
What happens if we call this URL?
http://example.com/app/accountView?id=' OR '1'='1
Validation can help, but it has its limitations. Client-side validation is mainly intended to improve user experience and does not provide real security, as it can easily be bypassed. Server-side validation is essential, but even then, there are often ways around it, for example by encoding input so it is not recognized.
The most effective solution is to use parameterized queries.
With parameterized queries, the SQL statement is defined using query text that includes parameters. The values for those parameters are then provided separately. The framework ensures that the query is handled correctly and prevents injected SQL code from being executed.
string sqlstr = "SELECT [name] FROM product where Listprice > @price ORDER BY [name]";
SqlCommand comm = new SqlCommand(sqlstr, conn);
SqlParameter priceParam = new SqlParameter("price", SqlDbType.Money);
priceParam.Value = searchPrice;
comm.Parameters.Add(priceParam);
The example above is written in C#, but similar approaches are available in other languages, such as PHP.
In this example, user input is no longer directly embedded in the query, but passed through the @price parameter. In the second-to-last line, the value of this parameter is set using the searchPrice variable, which contains the user input.
The parameter is then added to the command, allowing the query to be executed safely without the risk of injected SQL code being run. While frameworks like Entity Framework encourage secure practices, it is still possible to bypass them. That is why it is important to always use parameters to avoid introducing vulnerabilities.
Want to learn more?
At Betabit, we build and manage business-critical software, with security integrated from the very beginning. We use proven approaches such as threat modeling and Privacy by Design to identify and manage risks early.
We also share this knowledge through our training programs. We offer various training courses in security and software development to help strengthen your team.
If you would like to learn more about SQL injection or securing web applications, feel free to contact us or discuss your specific situation.
More blog posts
-
Threat modeling: from vulnerability to control
Threat modeling helps identify and manage risks early by analyzing threats, prioritizing them, and integrating security into the development process to prevent issues.Content typeBlog
-
Securing web applications and the OWASP Top 10
The OWASP Top 10 for 2025 highlights where web applications are truly vulnerable today and how you, as a developer, can tackle those risks in a targeted manner.Content typeBlog
-
Secure Your Software by Thinking Like a Hacker
To properly secure software, you must understand how hackers operate. Ethical hacking helps identify vulnerabilities in systems, processes, and human behavior.Content typeBlog
Stay up to date with our tech updates!
Sign up and receive a biweekly update with the latest knowledge and developments.