Java 在JDBC查询中使用表名作为参数的安全方法

Java 在JDBC查询中使用表名作为参数的安全方法,java,jdbc,dynamic,tablename,Java,Jdbc,Dynamic,Tablename,将表名作为参数放入SQL查询的安全方法是什么?不能使用将表名作为参数。连接字符串以使用动态表名执行查询是可能的,但不建议这样做,因为存在SQL注入的风险。最好的方法是什么?我会尝试解决设计问题,这样您就不必动态设置表名。如果这是不可能的,我会选择一种设计,在这种设计中,您可以管理一个可用表的列表,用户可以根据ID从中选择一个,这样您就可以从所选ID中检索真实的表名,并用它替换表名占位符,从而避免在表名替换中注入sql的任何机会 最好的方法是: 将表名放在用于分隔从一个数据库更改为另一个数据库的表

将表名作为参数放入SQL查询的安全方法是什么?不能使用将表名作为参数。连接字符串以使用动态表名执行查询是可能的,但不建议这样做,因为存在SQL注入的风险。最好的方法是什么?

我会尝试解决设计问题,这样您就不必动态设置表名。如果这是不可能的,我会选择一种设计,在这种设计中,您可以管理一个可用表的列表,用户可以根据ID从中选择一个,这样您就可以从所选ID中检索真实的表名,并用它替换表名占位符,从而避免在表名替换中注入sql的任何机会

最好的方法是:

  • 将表名放在用于分隔从一个数据库更改为另一个数据库的表名的字符之间
  • 并相应地转义提供的表名,这样SQL注入就不再可能了
  • 例如,在MySQL中,表名的分隔符是反引号字符,我们只需将其加倍即可对其进行转义

    如果您的查询是
    从条形图中选择foo
    ,则可以将查询重写为下一步:

     String query = String.format("SELECT foo from `%s`", tableName.replace("`", "``"));
    

    通过这种方式,您可以注入表名,而不必冒看到注入某些恶意代码的风险。

    在动态JDBC查询中只允许实际参数的背后有一个基本原理:参数可以来自外部,可以采用任何值,而表名和列名是静态的

    参数化表或列名可能有一些用例,主要是当不同的表具有几乎相同的结构时,并且由于DRY原则,您不希望重复多次相同的查询,而只更改表(或列名)。但是在这种情况下,程序员可以完全控制将被替换的名称,并且应该仔细测试它们中的任何一个都没有拼写错误=>这里没有SQL注入的可能性,并且在查询字符串中替换表名是安全的

    对于在internet上公开的web应用程序来说,这是完全不同的,其中查询将使用在表单字段中输入的内容,因为这里可能发生任何事情,如果您只是连接字符串而不是正确构建参数化查询,则包括一个半列以终止原始无害查询并伪造一个新的harmfull=>SQL注入


    我无法想象一个用例,其中表名或列名可以是用户在表单字段中键入的字符串,这是允许参数化它们的唯一原因。

    最好的方法是修复您的设计,这样您就不必动态地放置表名。不安全的原因是您失去了对要在数据库上执行的操作的控制。即使您执行强检查,您的设计也很弱,这将使您在性能、稳定性和安全性方面付出代价。那么为什么要这样做呢?如果只有一组可接受的表,那么查找表就可以工作(输入必须是其中包含的选项之一)。如果有一张桌子是可以接受的,我要问为什么?你正在开发类似mySQLAdmin的东西吗?我想如果你将输入限制为只有字母、数字、下划线,你应该是安全的(就注入而言,有人应该可以访问任何表,这仍然很奇怪)。那么查询的其余部分呢?列名之类的?你不需要这些也是非常动态的吗?如果tableName值是:
    “table”;GRANT…;PRINT'…“
    要使其工作,还应该检查tableName变量是否包含字母数字以外的字符…不,这不能工作,那么你必须从
    “table';GRANT…;PRINT'…
    中选择foo,它将使用反引号之间的内容作为表name@Bakus123好问题,我对SQLite的了解不多,但据我所知,您可以使用双引号或严重重音(为了与MySQL兼容)来引用标识符,因此应该使用相同的想法(将其加倍以逃避它)@NicolasFilotto,thx但是方括号呢?在文档中,他们写道它也可以用作引号标识符。@Bakus123它确实应该也可以使用,但如果我是你,我会使用双引号,因为它在SQLite中似乎更标准。我同意这是设计问题。它是一个后台运行的应用程序。正常用户不会选择值。它们由管理员配置。我喜欢配置ID和TABLENAME值对的想法。并在执行前检查实际表是否存在。