我写这个问题是因为我没有找到任何有关如何在Spring Data JPA中预防SQL注入的有用文章。所有的教程都展示了如何使用这些查询,但它们没有提及这些可能的攻击。
我有以下查询:
@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);
}
Rest控制器用于传递请求:
@RequestMapping(value = "/get-users", method = RequestMethod.POST)
public Response<StringResponse> getUsers(WebRequest request) {
return userService.getUsers(request.getParameter("email"));
}
在执行JPQL或本地查询参数之前,它们是否被转义?
以下是在我的MySQL控制台中执行SQL注入并删除用户表的查询:
SELECT * FROM users WHERE email LIKE '%'; DROP TABLE users; -- %';
我尝试通过向服务器发送POST请求来执行SQL攻击:
http://localhost:8080/get-users
POST: key/value: "email" : "'; DROP TABLE users; --"
我已启用了Hibernate的SQL日志记录,以下是该请求生成的内容:
[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; -- %]
表格没有被删除(这是好的),但为什么参数没有被转义?
如果我不注释@Param("emailAddress")
,而是使用索引参数,会怎样呢?
@Query(nativeQuery = true, value = "SELECT * FROM users WHERE email LIKE ?1")
public ResponseList<User> getUsers(String email);
like %:emailAddress%
、like ?1
、like %?1%
、like ?1%
、like %?1
都不会发生SQL注入。因为无论是名称参数还是位置参数,最终Hibernate都会生成本地SQL语句like ?
。 - RJ.Hwang