java - 在 Spring JPA 中避免 SQL 注入(inject)

标签 java sql spring spring-boot

我正在使用 sql 查询,例如

String query = "Select  max(case when UPPER(key)='firstname' then value end) as firstNameName, , ...   order by "+orderBy;
result = em.createNativeQuery(query).getResultList();
em.close();

出于某种原因,我将不得不使用动态 +orderBy 。其中 orderBy =firstname ASC,lastname DESC 等。尝试使用 .setParameter(1, orderedBy) 但在这种情况下,我没有得到预期的排序结果。

最佳答案

为了避免 sql 注入(inject)威胁,您首先需要删除附加参数到您的查询。当您在应用程序中附加参数时,攻击者可以劫持您的 sql 代码(例如使用撇号和其他方式)

例如:

如果您的查询是 "select * from table where name="+id

攻击者可以传递给字段值,例如: 'John' or 1=1; ->查看你在这个表中的所有记录

甚至 'John' or 1=1;Delete all from users;' -> 从用户表中删除所有条目。

劫持查询可以通过输入清理、输入白名单/黑名单(从输入中删除不需要的字符/定义允许或不允许的字符列表)等机制来避免。大多数现代框架框架(例如 JDBC/JPA/Hibernate)都可以提供针对这种威胁的保护。

综上所述,我们应该考虑以下情况:

考虑sql where参数:

例如 JDBC 提供准备好的语句,您可以在其中定义一个变量在您的 sql 中,然后由框架替换它

在你的情况下,JPA 实现(Hibernate)也有避免这种威胁的机制,也通过参数化查询和位置参数:

  1. 通过 native 查询位置参数:
Query q = em.createNativeQuery("SELECT count(*) FROM mytable where username = ?1");
q.setParameter(1, "test");

  1. 通过命名参数(jplq)
Query q = em.createQuery("SELECT count(*) FROM mytable where username = :username");
q.setParameter("username", "test");

考虑 orderBy 参数:

  1. CriteriaQuery/spring 规范
 CriteriaBuilder cb = this.entityManager
                .getCriteriaBuilder();
    CriteriaQuery<RESULT> criteria = cb.createQuery(RESULT.class);
    Root<RESULT> root = criteria.from(RESULT.class);
    return this.entityManager.createQuery(
                 criteria.select(root).orderBy(cb.asc(root.get("ORDER_BY_FIELD"))))
           .getResultList();

更多关于 criteriaQueries 的使用和配置 here

  1. 通过预先构建的 spring 特定 Sort 参数传递 orderBy(使用 spring-data 库)
Sort sort = Sort.by(Sort.Direction.ASC, "criteria");
em.createQuery(QueryUtils.applySorting(yourSqlQuery_withoutSorting,sort));

  1. 使用带有 spring-data 库的 @Query 注释方法:

您可以使用更少的样板代码(无需注入(inject) entityManager 和创建 nativeQuery)实现相同的结果,只需使用 @Query 注释来注释方法:

 @Query("select u from User u where u.lastname like ?1%")
  List<User> findByAndSort(String lastname, Sort sort);

注意:

本地与非本地(jpql): JOQL 查询独立于数据库供应商(MySQL、PostGres、Oracle、DB2),当您需要使用不同供应商不同的数据库特定功能时,nativeQueries 的使用更加集中。 举个简单的例子jpql不能支持原生[With] 2子句 PLSQL 标准函数

关于您的修改:

您可以尝试应用以下 sql 技巧进行动态排序:

SELECT param1, param2 ...
FROM ...
ORDER BY case when :sortParam='name asc' then name asc END
         case when :sortParam='name desc' then name desc END
         ....
         else 0


关于java - 在 Spring JPA 中避免 SQL 注入(inject),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63997976/

相关文章:

java - SwingEventMonitor 发生了什么?

java - 更改 Spring openapi-generator-maven-plugin 生成的接口(interface)的返回类型

java - 无法访问 Spring Boot 和 Jersey 应用程序中的某些 Controller

java - Spring PDF 生成 + i18n

Java Spring REST API 状态 400 对 POST/PUT 的响应

java - JRE 在不应出现的情况下给出 NullPointerException

java - Spring Boot/JUnit - 没有 'boolean' 类型的合格 bean 可用

sql - 在查询之前和之后获取行

java - JOOQ从表中获取记录并将其插入到另一个表中

sql - 行编号和子分组