如何使用 JPA 防止本机插入查询中的 SQL 注入?

How to prevent SQL injection in native insert query with JPA?

我正在使用 JPA/Hibernate 的本机查询在 PostgreSQL 上执行插入或更新 ("upsert"),具体取决于对象是否存在。代码如下所示:

val values: String = items.joinToString(", ", transform = this::convertItemToSqlValue)
val query = """
    insert into item (field1, field2)
    values $values
    on conflict on constraint item_pkey
    do update set 
        field1 = excluded.field1,
        field2 = excluded.field2
"""
entityManager.createNativeQuery(query).executeUpdate()

函数 convertItemToSqlValue 创建一个形式为 ('value a', 123) 的字符串。

位置参数 (values ?) 无效(并导致语法错误)。

如何防止 SQL 使用这种语句进行注入?

根据用户输入动态构建 SQL 语句并不是最好的主意。最好使用准备好的语句。但是,在这种情况下,似乎没有一种简单的方法可以使用 JPA EntityManager 执行补丁更新。

可以使用 JDBC 设置多个值。以下示例显示 Spring's JdbcTemplate:

的用法
val items: List<Item> = ...

val statement = 
    """
    insert into item (field1, field2)
    values (?,?)
    on conflict on constraint arbeit_pkey
    do update set 
        field1 = excluded.field1,
        field2 = excluded.field2
    """
jdbcTemplate.batchUpdate(
    statement, 
    object : BatchPreparedStatementSetter {
        override fun setValues(statement: PreparedStatement, index: Int) {
            val item = items[index]
            statement.setString(1, item.field1)
            statement.setInt(2, item.field2)
        }
        override fun getBatchSize(): Int = items.size
    }
)