我希望能更好地理解CallableStatement。 所以我的postgre数据库中有一个存储函数。
从java调用这些函数,其中参数是用户输入(HTTP POST参数)我不得不担心SQL注入。
在java中这样做:
String statementSQL = "SELECT my_function(" + toPostgresString(person.getEmail()) + "," + toPostgresString(person.getPhone()) + "," + toPostgresString(person.getDealType())+ ");";
其中
private static String toPostgresString(String value) {
if (value == null || value.equals("")) {
return POSTGRES.NULL;
} else {
return "'" + value + "'";
}
}
后一种方法确保所有参数都被视为字符串,但我读到,当参数是恶意的时,这种解决方案仍然很危险。
所以我尝试使用CallableStatements,因为它们被认为更安全。
CallableStatement statement = connection.prepareCall(" { call my_function( ?, ?, ? ) } ");
statement.setString(1, person.email());
statement.setString(2, person.phone());
statement.setString(3, person.getDealType());
statement.execute();
statement.close();
问题:在SELECT和CallableStatement这两种情况下,params被发送到数据库函数并在那里被视为函数本身定义的数据类型。 CallableStatement仅在数据类型不匹配时失败(在声明的函数和statement.set()中。
如果在两种情况下将params视为字符串(但在''之间),CallableStatement如何实际上比SELECT更安全。
感谢。
答案 0 :(得分:2)
PreparedStatement
和CallableStatement
都提供setXXX
方法来设置参数。它们实际上并没有对参数进行消毒,它们只是在线上使用二进制类型,因此“在两种情况下,params都被视为字符串”部分是错误的。
PreparedStatement
还提供了一些小的性能优势,因为在调用足够多次查询后,驱动程序实际上会创建一个服务器端预处理语句。
除非绝对必要,否则不应使用普通Statement
,并始终使用setXXX
方法,因为这就是它们的用途。
答案 1 :(得分:1)
据我所知,CallableStatement.setXXX()
为您清理参数。所以它不仅仅是简单的字符串连接。
另一方面,当你连接String时,你会发现令人讨厌的攻击,比如停止前面的语句,然后开始一个新的攻击:`&#39 ;;删除表用户; -
有关xkcd的更多信息,请参阅