I'm writing this question because I didn't find any useful article about how to prevent SQL Injection in Spring Data JPA. All the tutorials are showing how to use these queries but they don't mentioned anything about these possible attacks.
I'm having the following query:
@Repository
public interface UserRepository extends CrudRepository<User, Integer> {
@Query(nativeQuery = true, value = "SELECT * FROM users WHERE email LIKE %:emailAddress%")
public ResponseList<User> getUsers(@Param("emailAddress") String emailAddress);
}
The rest controller to deliver the request:
@RequestMapping(value = "/get-users", method = RequestMethod.POST)
public Response<StringResponse> getUsers(WebRequest request) {
return userService.getUsers(request.getParameter("email"));
}
Are JPQL or native query parameters escaped before executing them?
This is the query with SQL injection executed in my MySQL console which drops the users table:
SELECT * FROM users WHERE email LIKE '%'; DROP TABLE users; -- %';
I have tried to execute the SQL attack by sending a POST request to the server:
http://localhost:8080/get-users
POST: key/value: "email" : "'; DROP TABLE users; --"
I have enabled Hibernate's sql logging and this is what the above request produced:
[http-nio-8080-exec-8] DEBUG org.hibernate.SQL - SELECT * FROM users WHERE email LIKE ?
Hibernate: SELECT * FROM users WHERE email LIKE ?
[http-nio-8080-exec-8] DEBUG org.hibernate.loader.Loader - bindNamedParameters() %'; DROP TABLE users; -- % -> emailAddress [1]
[http-nio-8080-exec-8] TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [1] as [VARCHAR] - [%'; DROP TABLE users; -- %]
The table wasn't dropped (which is good) but why the parameter isn't escaped?
What if I don't annotate the @Param("emailAddress")
and I use indexed parameters?:
@Query(nativeQuery = true, value = "SELECT * FROM users WHERE email LIKE ?1")
public ResponseList<User> getUsers(String email);
Spring Data JPA uses bind parameters for all its features. There is very little String concatenation going on and that only with stuff that doesn't come from end users.
Therefore Spring Data JPA is secure against SQL injection.
What if I don't annotate the @Param("emailAddress") and I use indexed parameters?
This is independent of you using indexed or named parameters.
why the parameter isn't escaped?
Since the bind parameter values are not part of the SQL statement that gets parsed and converted into an execution plan in the database there is no need to escape the parameters. Indeed it would be a mistake to do so.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With