Spring Data JPA是Java生态中常用的持久层框架,它通过封装JPA规范简化了数据库操作的开发流程,默认情况下会对参数进行预编译处理,避免大部分SQL注入问题。但如果在项目中不当使用Native Query,依然可能让应用暴露在SQL注入风险之下。

Spring Data JPA的默认防注入机制
Spring Data JPA的JPQL查询和通过方法名派生的查询,默认会使用预编译语句(PreparedStatement)处理参数,框架会自动对传入的参数进行转义,避免参数被拼接为可执行的SQL片段。比如下面这个通过方法名派生的查询:
// 实体类定义
@Entity
public class User {
@Id
private Long id;
private String username;
private String password;
// 省略getter、setter
}
// Repository接口
public interface UserRepository extends JpaRepository<User, Long> {
// 方法名派生查询,框架会自动预编译参数
User findByUsername(String username);
}
上述代码中,调用findByUsername方法时,Spring Data JPA会自动生成预编译的SQL,传入的username参数不会被直接拼接到SQL语句中,因此不会出现注入问题。
Native Query为何会引入SQL注入风险
Native Query允许开发者直接编写原生SQL语句,绕过JPQL的预编译处理机制。如果开发者在编写Native Query时,直接将外部传入的不受信参数拼接到SQL字符串中,就会触发SQL注入漏洞。
漏洞触发场景示例
下面是一个存在SQL注入风险的Native Query实现:
@Repository
public class UserDao {
@PersistenceContext
private EntityManager entityManager;
// 存在风险的Native Query实现,直接拼接参数
public User unsafeFindByUsername(String username) {
String sql = "select * from user where username = '" + username + "'";
Query query = entityManager.createNativeQuery(sql, User.class);
List<User> resultList = query.getResultList();
return resultList.isEmpty() ? null : resultList.get(0);
}
}
如果攻击者传入的username参数为' or '1'='1,拼接后的SQL会变成select * from user where username = '' or '1'='1',这会查询出所有用户数据,造成数据泄露。如果传入更复杂的恶意参数,甚至可能被删表、篡改数据。
安全的Native Query写法
要避免Native Query的SQL注入问题,需要使用参数绑定的方式传入参数,而不是字符串拼接。正确的实现如下:
@Repository
public class UserDao {
@PersistenceContext
private EntityManager entityManager;
// 安全的Native Query实现,使用参数绑定
public User safeFindByUsername(String username) {
String sql = "select * from user where username = :username";
Query query = entityManager.createNativeQuery(sql, User.class);
query.setParameter("username", username);
List<User> resultList = query.getResultList();
return resultList.isEmpty() ? null : resultList.get(0);
}
}
上述代码中,通过:username占位符和setParameter方法绑定参数,框架会自动对参数进行预编译处理,避免注入风险。
禁用不受信的Native Query的建议
为了从根源上降低风险,建议遵循以下原则:
- 优先使用Spring Data JPA的JPQL查询或方法名派生查询,尽量避免使用Native Query
- 如果必须使用Native Query,禁止直接拼接外部传入的不受信参数,统一使用参数绑定方式
- 对Native Query的使用做代码审查,确保所有参数都通过预编译方式传入
- 如果业务需要动态拼接SQL条件,使用框架提供的条件构造器,比如JPA的Criteria API,避免手动拼接字符串
总结
Spring Data JPA本身提供了默认的防SQL注入保护,但Native Query的特性会绕过这些保护。开发者需要明确Native Query的风险点,避免不受信参数的直接拼接,通过参数绑定、优先使用JPQL等方式,保障数据库操作的安全性。只要规范Native Query的使用,就能有效避免这类注入漏洞。
Spring_Data_JPASQL注入Native_Query安全漏洞修改时间:2026-07-14 23:12:24