sql转义

irtuqstp  于 2021-06-30  发布在  Java
关注(0)|答案(1)|浏览(434)

我必须对参数进行转义,以避免sql注入问题。我有一个很大的criteriabuilder sql,在这里我可以找到下一个:

Expression<Integer> containsFunction = cb.function("CONTAINS", Integer.class,
    joinParty.get(MyEntity_.name), cb.literal(sb.toString())
);

这个“sb”是sqli所在的stringbuilder。不管怎样,这是一个不常见的(我不知道)句子在这个歌剧ón“ DEFINEMERGE “有明确的论点:

StringBuilder sb = new StringBuilder("DEFINEMERGE(((NEAR((");
for (int i = 0; i < nameValues.length; i++) {
    sb.append("{").append(nameValues[i]).append("}");
    if(i + 1 < nameValues.length) {
        sb.append(",");
    }
}
sb.append("),0)),(").append(nameValues[0]).append(" AND {").append(nameValues[1]).append("})");
if(nameValues.length > 3) {
    sb.append(",(").append(nameValues[1]).append(" AND {").append(nameValues[2]).append("})");
    if(nameValues.length == 4) {
        sb.append(",(").append(nameValues[2]).append(" AND {").append(nameValues[3]).append("})");
    }
}
sb.append("), AND, MIN)");

问题是有些fo的namevalues内部有一个“(”,破坏了sql。我不确定在这种情况下,安全化这些值的最佳方法是什么,因为这包含了一个sql字符串文本,而不是一个criteria对象。
这是生成的sql预期值:

CONTAINS(
    table.name, 
    'DEFINEMERGE (
        (
            (NEAR( (?, {?},{?}), 0, FALSE)),
            (? AND {?} and {?})
        ),
        AND,
        min 
    )'
    ,
    1
)

这是生成的查询的一个示例(隐藏表和字段的实名,以保护公司隐私和安全),它还具有参数bind数组:

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]
yhived7q

yhived7q1#

不幸的是,没有可靠的方法来转义sql,因为实际上没有“sql”这样的东西。这是方言,这是一个必要的信息位做的工作逃脱正确。那么,你想逃避什么呢?”“sql”不是一个可行的答案。可行的答案是‘postgres的sql’、‘mysql的sql’、‘oracle的sql’等等。sql更像是一个概念,而不是一个直接的规范(有一个实际的规范,但它包含的内容比你想象的要少得多,而且sql的每种方言都打破了这个规范,给它添加了很多东西)。
这就是为什么通常的建议是:真的,不,你不能做你想做的,你必须通过 .setX 上的方法 PreparedStatement 如果你想逃离这些东西。
从你的问题来看,似乎你的数据库中有实际的sql语句作为字符串文字,这本身就是一个奇怪的场景,而且很容易导致严重的安全问题,所以虽然你可能不想听到它,但这个设计需要彻底的修改,听起来好像其他代码会获取这个sql,然后逐字地运行它。
javascript曾经有过类似的经历( eval )由于eval是一个东西,安全漏洞的数量之多令人震惊。现在也有一些方法可以在你的网站上用头来禁止javascript中的eval,而浏览器则是围绕着出现在这些头中的url中的位来工作的,这是糟糕的-现代安全指南告诉你完全禁用这个功能,如果你想的话,你不能真正依赖它正常工作。
考虑到手动执行sql转义是一个非常糟糕的主意,我怀疑是否有任何库可以使用。您的jdbc驱动程序有一个很小的机会(深入研究这些类并查看网站!)有一个实用的方法可以做到这一点;考虑到每个方言都有不同的规则,这是有意义的:每个sql引擎都有不同的jdbc驱动程序。显然,如果您的jdbc驱动程序附带了一个sql转义工具,那么它就是该特定引擎的合适工具。
如果找不到,那么在大多数sql方言中,最简单的转义方法就是创建一个允许字符的白名单,并转义不在白名单上的每个字符。白名单应该只包含绝对安全的东西(a-z,0-9,也许——。清单上不应该出现类似引号或反斜杠的内容,我会避免使用$,因为它通常用于变量替换,这在sql中不是一件事,但比生产服务器更安全。
剩下的就可以逃走了。例如,在postgres中,您可以将字符串: Joe's bar & Grill 进入之内 E'Joe\u0027s bar \u0026 Grill' 这个 E 意思是:带转义符的字符串。该算法检查每个字符并复制白名单上的所有字符。引号和符号不在上面,所以它们被替换为 \u0000 其中零是字符的十六进制编码(字符的值) s.charAt(i) ,强制转换为整数,打印为十六进制数)>
这应该涵盖了所有的基础,但请注意(叹气)转义字符串完全超出了sql规范,它是postgresim。

相关问题