Careeroza
SQL Injection
Never Build SQL by Concatenation
Example
If user input is pasted into the SQL string, the user can change the query itself. Watch what a search box receives from an attacker:
public class Main {
static String unsafeLogin(String email, String password) {
return "select * from users where email = '" + email + "' and password = '" + password + "'";
}
public static void main(String[] args) {
System.out.println("Normal user:");
System.out.println(unsafeLogin("[email protected]", "Pass@123"));
System.out.println("Attacker:");
System.out.println(unsafeLogin("[email protected]' --", "anything"));
System.out.println("Attacker 2:");
System.out.println(unsafeLogin("x' OR '1'='1", "x' OR '1'='1"));
}
}Output
Normal user: select * from users where email = '[email protected]' and password = 'Pass@123' Attacker: select * from users where email = '[email protected]' --' and password = 'anything' Attacker 2: select * from users where email = 'x' OR '1'='1' and password = 'x' OR '1'='1'
In the first attack, -- starts an SQL comment, so the password check disappears and the attacker logs in as admin. In the second, OR '1'='1' is always true and every user row is returned.
The Fix: Parameters
// SAFE: the driver sends the value separately from the SQL text
PreparedStatement ps = conn.prepareStatement(
"select * from users where email = ? and password_hash = ?");
ps.setString(1, email); // "[email protected]' --" is treated as plain text
ps.setString(2, hash);- With
?parameters the input can never become SQL code. - Hibernate and Spring Data JPA always use parameters for
find,persist, derived queries and JPQL with:nameparameters. - You can still create injection in JPA if you concatenate strings into JPQL or native SQL. Always bind parameters.
Note: Also never store plain passwords; store a BCrypt hash. See the Spring Security material.