OWASP Top 10:2021 (JAVA)
A SQL Injection is not a new or overly complicated type of attack, yet it continues to sit atop the OWASP Top Ten Application Security Risks after more than 20 years of it having been publicly utilized. This is primarily due to its inherent relative ease of use, coupled with its severity of impact when directed toward the staggeringly high number of websites with poorly written, vulnerable code.
SQL is a query language that is designed to access, modify, and delete data stored in relational databases. Numerous web applications and websites use SQL databases as their method of data storage. Applications with a higher prevalence of older functional interfaces such as PHP and ASP are relatively more susceptible to SQL Injection flaws than applications based on more recent technologies.
Applications are vulnerable to attacks when user-supplied data is not validated, filtered for escape characters or sanitized by the application.
An attacker can use SQL Injection to manipulate an SQL query via the input data from the client to the application, thus forcing the SQL server to execute an unintended operation constructed using untrusted input.
A successful SQL Injection attack can result in a malicious user gaining complete access to all data in a database server with the ability to execute unauthorized SQL queries and compromise the confidentiality, integrity, and availability of the application. Depending on the backend DBMS used and the permissions granted to the user on the database, a SQL Injection could result in arbitrary file read/write and even remote code execution.
The severity of attacks that have leveraged SQL Injection should not be understated. Notorious breaches, including the devastating and internationally renowned hacks of Sony Pictures and LinkedIn, for example, are reported to have been executed using SQL Injection.
Subverting application logic through SQL can lead to unpredictable outcomes depending on the context of the SQL statement the strategy of the attacker.
There are well-known exploitation techniques that attackers leverage depending on the vulnerability within the implementation of the code:
- Manipulating an SQL query logic to bypass access controls.
- Retrieving hidden data to return additional results, including data from other tables within the databases, e.g., leveraging the
- Executing arbitrary SQL code in the context of the database whether stacked queries are allowed.
Accessing files and executing commands in the operating system, depending on the vulnerable code and the database management system.
It is called blind SQL Injection when the injection succeeds, but the code doesn’t return the result of the manipulated query to the attacker. Blind injections are still exploitable to retrieve the content using timing analysis, content analysis, or other out-of-bound techniques.
The following is a classic example of subverting application logic to bypass access controls.
Usernames and passwords are ubiquitous as the method for logging into applications. In this benign scenario, a user submits the username
user and the password
secret. The application then performs a SQL query to verify the credentials:
SELECT * FROM users WHERE username = 'user' AND password = 'secret'
The login is successful if the query returns the details of the user. If the query doesn’t return the user details, it is rejected.
By leveraging single quotes and SQL comments (
--), it is possible to log in as any user without a password, as the password check from the WHERE clause is removed from the query.
The following example illustrates this in action. By entering
administrator'-- in the username field and leaving the password field blank, the SQL statement would result as the following:
SELECT * FROM users WHERE username = 'administrator'--' AND password = '
The database evaluates this statement without the commented out part, executing just the first part:
SELECT * FROM users WHERE username = 'administrator'
Since the manipulated query always returns the details of the
administrator user, the attacker can successfully log in without knowing the correct password.
To avoid SQL Injection vulnerabilities, developers need to use parameterized queries, specifying placeholders for parameters so that they are not considered as a part of the SQL command; rather, as solely data by the database.
When working with legacy systems, developers need to escape inputs before adding them to the query. Object Relational Mappers (ORMs) make this easier for the developer; however, they are not a panacea, with the underlying mitigations still entirely relevant: untrusted data needs to be validated, query concatenation should be avoided unless absolutely necessary, and minimizing unnecessary SQL account privileges is crucial.
Verify that where parameterized or safer mechanisms are not present, context-specific output encoding is used to protect against injection attacks, such as the use of SQL escaping to protect against SQL Injection.
- OWASP ASVS:5.3.5
- OWASP Testing Guide: Testing for SQL Injection
Vulnerable example for JAVA:
The following snippet contains a Java application that runs an SQL query to resolve the host supplied by the user.
String query = "SELECT account_number, account_balance FROM customer_data WHERE account_owner_id = " + request.getParameter("id");
Statement statement = connection.createStatement( ... );
ResultSet res = statement.executeQuery( query );
Since the SQL query is built concatenating
id user inputs, an attacker could manipulate the query to disclose other people's data and even affect the integrity of the database, depending on the used database engine.
For example, by injecting
123 OR 1=1;--in the
id field, the SQL query becomes:
SELECT account_number, account_balance FROM customer_data WHERE account_owner_id = 123 OR 1=1;--
The manipulated query returns any entry in the
customer_data table that has an owner id
123 or if
1. The query statement is then terminated commenting out any trailing code using
;--. Since the
WHERE statement is always true, the query returns all of the orders of all of the customers.
Java provides the
PreparedStatement method of the
Connection object database to perform parameterized queries on most of the database technologies available.
String custid = request.getParameter("id");
String query = "SELECT account_number, account_balance FROM customer_data WHERE account_owner_id = ?"
PreparedStatement pstmt = connection.prepareStatement( query );
pstmt.setString( 1, custid);
ResultSet results = pstmt.executeQuery( );