【问题标题】:Can I pass table name as argument to a java prepared statement?我可以将表名作为参数传递给 java 准备好的语句吗?
【发布时间】:2012-07-25 07:30:54
【问题描述】:

我正在用 Java 为我的 Tomcat 服务器应用程序编写一个 DAO 层,

我希望使用 Prepared Statement 包装我的查询(1. 解析一次查询,2. 防御 SQL 注入), 我的数据库设计包含每个数据源系统的 MyISAM 表。而且大多数通过 DBO 的查询都是使用不同的表名作为参数的选择。

其中一些表可能是即时创建的。

我已经浏览了许多解释我可能不会使用表名作为 Prepared 语句的参数的帖子。

我找到了建议使用某种类型的函数(例如 mysql_real_escape_string)的解决方案,这些函数可以处理此参数并将结果作为字符串附加到查询中,

是否有任何内置的 Jave 库函数可以以最佳优化方式执行此操作,或者您可能建议在 DAO 层中执行其他操作(我不喜欢将任何例程添加到它自己的 DB 中) ?

【问题讨论】:

    标签: java mysql prepared-statement dao tablename


    【解决方案1】:

    您可以对表名应用限制吗?这可能比引用更容易。例如,如果您可以说所有表名都必须匹配 [0-9A-Za-z_]+ 的正则表达式,那么我认为您不需要任何引用。如果您需要空格,您可以使用`table name` 来避免总是 - 但同样,不必担心“完整”引用。

    限制可用的东西通常比处理所有可能性要简单得多:)

    【讨论】:

    • 目前,我可能会尝试通过正则表达式来限制表名,虽然我相信 SQL 注入仍然可能会尝试绕过这个限制,通过使用相同的允许字母,我仍然想要求一些健壮性在表名中,我将来可能会添加一个加密的表名,另外我想获得在准备好的语句中解析一次的优势,除了限制它还有其他解决方案吗?
    • @Michael:SQL 注入攻击如何绕过该限制?如果您 允许使用字母数字值(理想情况下也有长度限制),那么就可以消除 SQL 注入的可能性。我不相信你可以创建一个PreparedStatement,当每次都有不同的表时,它会被解析一次。除了其他任何事情,准备好的语句的部分好处是缓存的查询计划,当您更改表时这将没有意义。
    • fyi,mysql 使用反引号(不是[...])来分隔“非标准”架构元素名称
    • @Bohemian:谢谢,会编辑的。(是的,SO Markdown 中的反引号很痛苦 :)
    • 如果您想更加安全,可以准备SHOW TABLES WHERE tables = ? 并使用提供的表名调用它以检查它是否真的存在。 (WHERE 条件可能需要更正,因为我现在手头没有 mysql)。
    【解决方案2】:

    如果您想更加安全,可以准备一个查询并使用提供的表名调用它以检查它是否真的存在:

    PreparedStatement ps = conn.prepareStatement("SHOW TABLES WHERE tables = ?");
    ps.setString(1, nameToCheck);
    if(!ps.executeQuery().next())
      throw new RuntimeException("Illegal table name: " + nameToCheck);
    

    WHERE 条件可能需要一些修正,因为我现在手头没有 mysql)。

    【讨论】:

    • 谢谢我喜欢这个答案,我认为正确的语法是“SHOW TABLES LIKE = ?”,你也可以在 MySQL 中使用这个语法:SELECT 1 FROM information_schema.tables WHERE table_schema = ? AND table_name = ?
    • @Michael 是的,使用information_schema 更好,因为它更便携——应该适用于任何 ANSI SQL 兼容的 DBMS。但请记住,例如PostgreSQL 实现了模式/模式,所以你应该在WHERE 子句中再添加一个AND 以避免匹配相邻模式中的表。
    猜你喜欢
    • 1970-01-01
    • 2012-07-03
    • 1970-01-01
    相关资源
    最近更新 更多