This post explains how to test websites for time-based SQL injections in modern environments.
Important: This information is provided solely for the purpose of educating security professionals about the threats and how to prevent such attacks.
Time-based SQL injection is a type of attack in which a malicious hacker tests a website for vulnerabilities by measuring the time it takes for a database to respond. They inject SQL code into a data input field, such as a search field or form, to intentionally cause the database to respond slowly.
Instead of displaying errors or returning data directly, as is the case with other methods, time-based SQL injection only shows the attacker whether a delay has occurred. For example, an attacker could use an SQL query like this:
1' OR IF(1=1, SLEEP(5), 0) --
In this example, if the database is vulnerable, it will wait 5 seconds before responding. This delay confirms that the database is compromised.
The effectiveness of time-based SQL injection relies heavily on direct and seamless communication with the database, which can be disrupted by modern environments with reverse proxies, cache servers, and other optimizations.
Modern web environments often include features such as reverse proxies, caching, and content delivery networks (CDNs) to improve performance and handle high traffic. These features can thwart security checks, including time-based SQL injections.
How Caching and Proxies Affect Time-Based SQL Injection
A common example is a reverse proxy with caching. When a pentester (or hacker) sends a request with a time-based SQL injection payload, such as 1′ OR IF(1=1, SLEEP(5), 0) —, the first request may reach the database and cause a 5-second delay, indicating a possible vulnerability. But when caching is enabled, the proxy can store this response. For repeated identical requests, the response may be served from the cache without being executed by the database. This can lead the pentester to mistakenly believe that the vulnerability is a false positive or does not exist because the expected delay does not occur.

Test Scenario for Testing Time-Based SQL Injection
This test shows how a caching reverse proxy such as Nginx can affect testing for time-based SQL injection vulnerabilities. By configuring Nginx as a reverse proxy with caching enabled, you can see how duplicate requests are handled differently.
Configuring Nginx for Reverse Proxy and Caching
Nginx is configured to be used as a reverse proxy for a PHP backend application connected to a database:
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60s;
server {
listen 80;
# Configure the backend service
location / {
proxy_pass http://web:80;
proxy_cache my_cache; # Enable caching
proxy_cache_bypass $arg_cache_bypass; # Allows cache bypass if needed
proxy_cache_valid 200 10s; # Cache successful responses for 10 seconds
add_header X-Cache-Status $upstream_cache_status;
}
}
Configuring Docker Compose
Here is a basic example of a docker-compose.yml file that configures an environment with Nginx as a reverse proxy, a PHP application with a vulnerable endpoint, and a MySQL database.
Database Service (MySQL Database):
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: test
MYSQL_USER: tim
MYSQL_PASSWORD: test
ports:
- 3306:3306
volumes:
- ./dump:/docker-entrypoint-initdb.d
restart: always
container_name: mysql_database
This initializes the MySQL database with data from dump.sql, providing a test database for SQL injection.
Web Service (PHP Web Application):
web:
build:
context: ./
container_name: php_web
depends_on:
- db
volumes:
- ./php/:/var/www/html/
ports:
- 8080:80
stdin_open: true
tty: true
restart: always
This service launches the vulnerable PHP application, binding it to the database and making it available on port 8080.
Reverse Proxy Service (Nginx Reverse Proxy):
rp:
image: nginx:latest
depends_on:
- web
ports:
- 80:85
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
restart: always
container_name: reverse_proxy
This acts as a reverse proxy. It also uses a custom configuration from nginx.conf to enable caching.
Sending Payloads

The payload was successfully executed and the response was delayed for 5 seconds (X-Cache-Status: MISS).

But the second response was delayed by only 13 ms due to the cache server response.
Cache Bypass Methods
Adding unique parameters: By adding a random or unique parameter to each request, caching engines treat each request as a new one. For example, &cachebuster=12345 can be added to the end of the URL, where 12345 is a random number that changes with each request.

Using decimal numbers: By making small adjustments to the delay value (e.g., 5.0 instead of 5), caching engines treat each request as unique due to the difference in the structure of the request. For example, using SLEEP(5) in one request and SLEEP(5.0) in the next may prevent the caching layer from recognizing them as identical.

Using arithmetic operations: By adding them to the delay function (e.g. SLEEP(3+2) or SLEEP(10/2) instead of SLEEP(5)), caching engines interpret each request as unique due to the difference in the query structure.

Adding comments to payloads: By inserting random comments into the SQL payload, each request can be made unique. Here is an example:

Using redundant expressions in payloads: Adding harmless expressions like 123=123 makes each query unique to caching engines, while keeping the SQL logic unchanged. Here’s how it works for the query 1′ OR IF(1=1, SLEEP(5), 0) AND 123=123 —:

Why This Approach Is Needed
While testing for time-based SQL injection, a problem arose after implementing a cache server. When the test was repeated with it, the response was served directly from the cache for identical requests after the first, returning instantly without re-executing the SQL query. As a result, no SQL injection was found because the caching mechanism masked the latency that would normally indicate a successful injection. This shows how caching layers can disrupt time-based testing by providing immediate, cached responses that bypass the server-side entirely, resulting in missed detections.
Scan results without a cache server (vulnerability found):

Scan results with a cache server (vulnerability not found):

Detecting Time-Based SQL Injections
To find such vulnerabilities, you can use the Invicti platform, which finds a large number of complex flaws like this one.
To test this solution for free, leave your contact details below and we will contact you:







