Gau*_*rav 9 java db2 jdbc oracle12c
我有这样的代码.
final PreparedStatement stmt = connection
.prepareStatement("delete from " + fullTableName
+ " where name= ?");
stmt.setString(1, addressName);
Run Code Online (Sandbox Code Playgroud)
计算fullTableName是这样的:
public String getFullTableName(final String table) {
if (this.schemaDB != null) {
return this.schemaDB + "." + table;
}
return table;
}
Run Code Online (Sandbox Code Playgroud)
这schemaDB是环境的名称(可以随时间更改),table是表名(将被修复).
值schemaDB来自一个XML文件,使查询易受SQL注入攻击.
查询:我不确定如何将表名用作预准备语句(如name本示例中所使用的),这是针对SQL注入的100%安全措施.
任何人都可以建议我,可能有什么方法可以解决这个问题?
注意:我们将来可以迁移到DB2,因此该解决方案应该与Oracle和DB2兼容(如果可能的话,与数据库无关).
遗憾的是,JDBC不允许您将表名作为语句内的绑定变量.(这有其原因).
所以你不能写,或实现这种功能:
connection.prepareStatement("SELECT * FROM ? where id=?", "TUSERS", 123);
Run Code Online (Sandbox Code Playgroud)
并且必须TUSER绑定到语句的表名.
因此,您唯一安全的方法是验证用户输入.但最安全的方法不是验证它并允许用户输入通过数据库,因为从安全的角度来看,您总是可以指望用户比验证更聪明.永远不要相信在您的语句中连接的动态用户生成的String.
那么什么是安全的验证模式?
1)在代码中一劳永逸地创建所有有效语句.
Map<String, String> statementByTableName = new HashMap<>();
statementByTableName.put("table_1", "DELETE FROM table_1 where name= ?");
statementByTableName.put("table_2", "DELETE FROM table_2 where name= ?");
Run Code Online (Sandbox Code Playgroud)
如果需要,可以使用select * from ALL_TABLES;语句将此创建本身变为动态.ALL_TABLES将返回您的SQL用户有权访问的所有表,您还可以从中获取表名和模式名称.
2)选择地图内的语句
String unsafeUserContent = ...
String safeStatement = statementByTableName.get(usafeUserContent);
conn.prepareStatement(safeStatement, name);
Run Code Online (Sandbox Code Playgroud)
查看unsafeUserContent变量如何永远不会到达DB.
3)制定某种策略或单元测试,以检查statementByTableName您的模式是否有效,以便将来进行演变,并且不会丢失任何表格.
你可以1)使用免注入查询验证用户输入确实是一个表名(我在这里输入伪sql代码,你必须调整它才能使它工作,因为我没有Oracle实例来实际检查有用) :
select * FROM
(select schema_name || '.' || table_name as fullName FROM all_tables)
WHERE fullName = ?
Run Code Online (Sandbox Code Playgroud)
并在此处将您的fullName绑定为预准备语句变量.如果您有结果,那么它是一个有效的表名.然后,您可以使用此结果来构建安全查询.
它是1到2之间的混合.您创建一个名为"TABLES_ALLOWED_FOR_DELETION"的表,并使用适合删除的所有表静态填充它.
然后进行验证步骤
conn.prepareStatement(SELECT safe_table_name FROM TABLES_ALLOWED_FOR_DELETION WHERE table_name = ?", unsafeDynamicString);
Run Code Online (Sandbox Code Playgroud)
如果有结果,则执行safe_table_name.为了更加安全,标准应用程序用户不应该写入此表.
我不知何故觉得第一种模式更好.
| 归档时间: |
|
| 查看次数: |
2594 次 |
| 最近记录: |