Java 无PreparedStatements条件API的SQL Escape

Java 无PreparedStatements条件API的SQL Escape,java,criteria,criteria-api,Java,Criteria,Criteria Api,我必须转义一个参数以避免SQL注入问题。我有一个大的CriteriaBuilder SQL,在这里我可以找到下一个: Expression<Integer> containsFunction = cb.function("CONTAINS", Integer.class, joinParty.get(MyEntity_.name), cb.literal(sb.toString()) ); 问题是,一些名称值有一个内部的,破坏了SQL。我不确定在这种情况

我必须转义一个参数以避免SQL注入问题。我有一个大的CriteriaBuilder SQL,在这里我可以找到下一个:

Expression<Integer> containsFunction = cb.function("CONTAINS", Integer.class,
    joinParty.get(MyEntity_.name), cb.literal(sb.toString())
);
问题是,一些名称值有一个内部的,破坏了SQL。我不确定在这种情况下,安全化这些值的最佳方法是什么,因为这包含了一个SQL字符串文本,而不是一个criteria对象

这是预期生成的SQL语句:

CONTAINS(
    table.name, 
    'DEFINEMERGE (
        (
            (NEAR( (?, {?},{?}), 0, FALSE)),
            (? AND {?} and {?})
        ),
        AND,
        min 
    )'
    ,
    1
)
这是一个为公司隐私和安全性生成的查询隐藏表和字段的真实名称的示例,它也有参数绑定数组:

SELECT 
    COUNT(t0.<VALUE>) 
FROM 
    SCHEME.<TABLE_NAME> t0 
    LEFT OUTER JOIN SCHEME.<TABLE_NAME> t2 ON (t2.<VALUE> = t0.<VALUE>) 
    LEFT OUTER JOIN SCHEME.<TABLE_NAME> t6 ON (t6.<VALUE> = t2.<VALUE>) 
    LEFT OUTER JOIN SCHEME.<TABLE_NAME> t7 ON (t7.<VALUE> = t6.<VALUE>) 
    LEFT OUTER JOIN SCHEME.<TABLE_NAME> t8 ON (t8.<VALUE> = t7.<VALUE>) 
    LEFT OUTER JOIN SCHEME.<TABLE_NAME> t3 ON (t3.<VALUE> = t2.<VALUE>) 
    LEFT OUTER JOIN SCHEME.<TABLE_NAME> t4 ON (t4.<VALUE> = t3.<VALUE>) 
    LEFT OUTER JOIN SCHEME.<TABLE_NAME> t5 ON (t5.<VALUE> = t4.<VALUE>), 
    SCHEME.<TABLE_NAME> t11, 
    SCHEME.<TABLE_NAME> t10, 
    SCHEME.<TABLE_NAME> t9, 
    SCHEME.<TABLE_NAME> t1 
WHERE 
    ((((((((((((((((t0.<VALUE> IN (?)) AND (t0.<VALUE> IN (?))) AND (t6.<VALUE> = ?)) AND (t3.<VALUE> IN (?))) AND ((t2.<VALUE> IS NULL) OR (t2.<VALUE> = t9.<VALUE>))) AND (t0.<VALUE> = ?)) AND (CONTAINS(t1.<VALUE>, ?) > ?)) AND (t0.<VALUE> IN (?))) AND (t1.<VALUE> = ?)) AND t0.<VALUE> IN (SELECT t12.<VALUE> FROM SCHEME.<TABLE> t14 LEFT OUTER JOIN SCHEME.<TABLE> t16 ON (t16.<VALUE> = t14.<VALUE>), SCHEME.<TABLE> t13, SCHEME.<TABLE> t12, SCHEME.<TABLE> t15 WHERE ((((((t13.<VALUE> IN (?)) AND (t14.<VALUE> IN (?))) AND (t14.<VALUE> <= ?)) AND ((t14.<VALUE> IS NULL) OR (t14.<VALUE> >= ?))) AND (t16.<VALUE> = ?)) AND (((t14.<VALUE> = t13.<VALUE>) AND (t12.<VALUE> = t13.<VALUE>)) AND (t15.<VALUE> = t14.<VALUE>))))) AND (t9.<VALUE> IN (?))) AND (t11.<VALUE> IN (?))) AND (t0.<VALUE> = t11.<VALUE>)) AND (t9.<VALUE> <= ?)) AND ((t9.<VALUE> IS NULL) OR (t9.PARO_DA_END_VALIDITY >= ?))) AND (((t9.<VALUE> = t0.<VALUE>) AND (t1.<VALUE> = t0.<VALUE>)) AND (t10.<VALUE> = t9.ROTY_ID_ENGAGED_ROLE_SPEC)))

    bind => [1, INDI, 1, 1, 1, DEFINEMERGE(((NEAR(({(name},{name)}),0)),((name AND {name)})), AND, MIN), 0, 1, 1, 1, 1, 2020-09-07 00:00:00.0, 2020-09-07 00:00:00.0, 1, 1, 1, 2020-09-07 00:00:00.0, 2020-09-07 00:00:00.0]

不幸的是,没有可靠的方法来转义SQL,因为实际上没有“SQL”这样的东西。这里有方言,这是一个必要的信息位来完成正确的逃跑工作。那么,你想逃避什么?”“SQL”不是一个可行的答案。可行的答案是‘postgres的SQL’、‘MySQL的SQL’、‘Oracle的SQL’等等。SQL更像是一个概念,而不是一个直接的规范。有一个实际的规范,但它包含的内容比你想象的要少很多,而SQL的每种方言都打破了这个规范,并为它添加了大量的内容

这就是为什么通常的建议是:真的,不,你不能做你想做的,如果你想逃避这些东西,你必须通过PreparedStatement上的.setX方法

从您的问题来看,您的数据库中似乎有实际的SQL语句作为字符串文本,这本身就是一个奇怪的场景,而且很容易导致严重的安全问题,因此,尽管您可能不想听到它,但此设计需要完全返工,听起来好像其他代码会抓取这个SQL,然后逐字运行它

Javascript有一段时间是这样的eval,由于eval是一种东西,因此发生的安全泄漏的数量之多令人震惊。现在也有一些方法可以使用标题来禁止你网站上javascript中的eval,浏览器可以绕过出现在这些标题中的URL中的位,但糟糕的是,现代安全指南告诉你完全禁用这个功能,如果你想的话,你不能真正依靠它正常工作

考虑到使用SQL转义是一个非常糟糕的主意,我怀疑是否有任何库可以使用。您的JDBC驱动程序很有可能深入这些类并查看网站!有一个实用的方法可以做到这一点;考虑到每种方言都有不同的规则,这是有道理的:每个SQL引擎都有不同的JDBC驱动程序。显然,如果您的JDBC驱动程序附带了SQL转义工具,那么它就是该特定引擎的正确工具

如果您找不到,在大多数SQL方言中,最简单的转义方法是创建一个允许字符的白名单,并转义不在白名单上的每个字符。白名单应该只包含绝对安全的东西a-z,0-9,也许——。列表中不应该出现类似于引号或反斜杠的内容,我会避免使用$,因为它通常用于变量替换,这在SQL中不是一件事,但比您的生产服务器更安全

剩下的就可以逃脱了。例如,在postgres中,您可以打开字符串:

乔的酒吧和烧烤店

进入

E'Joe\u0027s酒吧\u0026烧烤店'

E的意思是:带转义符的字符串。算法检查每个字符并复制白名单上的所有字符。引号和符号不在其上,因此它们被替换为\u0000,其中零是字符的十六进制编码s.charAti的值,转换为int,打印为十六进制数>


这应该涵盖所有基础,但请注意,转义字符串完全超出了SQL规范,这是一个postgresism。

当前代码生成的SQL是什么?用一个示例更新
SELECT 
    COUNT(t0.<VALUE>) 
FROM 
    SCHEME.<TABLE_NAME> t0 
    LEFT OUTER JOIN SCHEME.<TABLE_NAME> t2 ON (t2.<VALUE> = t0.<VALUE>) 
    LEFT OUTER JOIN SCHEME.<TABLE_NAME> t6 ON (t6.<VALUE> = t2.<VALUE>) 
    LEFT OUTER JOIN SCHEME.<TABLE_NAME> t7 ON (t7.<VALUE> = t6.<VALUE>) 
    LEFT OUTER JOIN SCHEME.<TABLE_NAME> t8 ON (t8.<VALUE> = t7.<VALUE>) 
    LEFT OUTER JOIN SCHEME.<TABLE_NAME> t3 ON (t3.<VALUE> = t2.<VALUE>) 
    LEFT OUTER JOIN SCHEME.<TABLE_NAME> t4 ON (t4.<VALUE> = t3.<VALUE>) 
    LEFT OUTER JOIN SCHEME.<TABLE_NAME> t5 ON (t5.<VALUE> = t4.<VALUE>), 
    SCHEME.<TABLE_NAME> t11, 
    SCHEME.<TABLE_NAME> t10, 
    SCHEME.<TABLE_NAME> t9, 
    SCHEME.<TABLE_NAME> t1 
WHERE 
    ((((((((((((((((t0.<VALUE> IN (?)) AND (t0.<VALUE> IN (?))) AND (t6.<VALUE> = ?)) AND (t3.<VALUE> IN (?))) AND ((t2.<VALUE> IS NULL) OR (t2.<VALUE> = t9.<VALUE>))) AND (t0.<VALUE> = ?)) AND (CONTAINS(t1.<VALUE>, ?) > ?)) AND (t0.<VALUE> IN (?))) AND (t1.<VALUE> = ?)) AND t0.<VALUE> IN (SELECT t12.<VALUE> FROM SCHEME.<TABLE> t14 LEFT OUTER JOIN SCHEME.<TABLE> t16 ON (t16.<VALUE> = t14.<VALUE>), SCHEME.<TABLE> t13, SCHEME.<TABLE> t12, SCHEME.<TABLE> t15 WHERE ((((((t13.<VALUE> IN (?)) AND (t14.<VALUE> IN (?))) AND (t14.<VALUE> <= ?)) AND ((t14.<VALUE> IS NULL) OR (t14.<VALUE> >= ?))) AND (t16.<VALUE> = ?)) AND (((t14.<VALUE> = t13.<VALUE>) AND (t12.<VALUE> = t13.<VALUE>)) AND (t15.<VALUE> = t14.<VALUE>))))) AND (t9.<VALUE> IN (?))) AND (t11.<VALUE> IN (?))) AND (t0.<VALUE> = t11.<VALUE>)) AND (t9.<VALUE> <= ?)) AND ((t9.<VALUE> IS NULL) OR (t9.PARO_DA_END_VALIDITY >= ?))) AND (((t9.<VALUE> = t0.<VALUE>) AND (t1.<VALUE> = t0.<VALUE>)) AND (t10.<VALUE> = t9.ROTY_ID_ENGAGED_ROLE_SPEC)))

    bind => [1, INDI, 1, 1, 1, DEFINEMERGE(((NEAR(({(name},{name)}),0)),((name AND {name)})), AND, MIN), 0, 1, 1, 1, 1, 2020-09-07 00:00:00.0, 2020-09-07 00:00:00.0, 1, 1, 1, 2020-09-07 00:00:00.0, 2020-09-07 00:00:00.0]