【问题标题】:How to pass PreparedStatement setArray for character array如何为字符数组传递 PreparedStatement setArray
【发布时间】:2012-12-20 13:25:57
【问题描述】:

我有一些JDBC代码如下:

String selectSQL = "SELECT * FROM DBUSER WHERE USER_ID = ? and PASSWORD = ?";

Integer userId = 1000;
char[] passwordString = new char[] { 't', 'e', 's', 't' };

PreparedStatement preparedStatement = dbConnection.prepareStatement(selectSQL);
preparedStatement.setInt(1, 1001);
preparedStatement.setArray(2,... ??? // how to do this part?

// execute select SQL statement
ResultSet rs = preparedStatement.executeQuery();

如何调用preparedStatement.setArray 设置查询中的第二个参数?我不想在这里使用字符串参数来保护密码。

请注意,我正在使用 Hypersonic DB,但如果有用的话,我计划迁移到 MySql。

【问题讨论】:

  • 我不确定你想这样做。
  • 为什么?我希望避免使用String,因为我知道将密码合二为一存在一定的安全风险。
  • 这种情况下没有问题,如果不使用preparedstatement(sql注入)就有问题
  • 我认为加盐和加密的密码会更好。

标签: java jdbc


【解决方案1】:

PreparedStatement#setArray 收到了java.sql.Array 首先你应该使用 JDBC Conncetion 的createArrayOf 方法来创建数组,然后你才能将它传递给setArray

由于该方法只接受Object[],因此您应该创建一个Character 数组而不是char。

例如:

Character[] passwordString = new Character[] { 't', 'e', 's', 't' };
Array sqlArray = con.createArrayOf("CHAR", passwordString);
preparedStatement.setArray(2, sqlArray);

【讨论】:

  • 首先你应该知道db中的类型是一个ARRAY
  • 您需要提供the SQL name of the type the elements of the array map to(即元素的类型而不是数组本身)
  • 你没有明白。那么数据库中的列类型应该是Array。然后你可以使用java.sql.Array。这种类型允许您在单行中存储多个数据,而无需任何额外的关系。它不是按照您试图暗示的方式设计的。
  • 啊,是的,列类型是ARRAY,我的意思是什么?
  • 不常用这种类型来存储数据,因为您已预设为解决方案。
【解决方案2】:

如果你想在准备好的语句中传递一个数组,只需调用

preparedStatemtn.setArray(index,array);

但您首先必须确保的是,在您的数据库中,该列也是ARRAY。有关详细信息,请参阅 Aviram Sagal 的回答。


但你的基地认为它是为了保护密码。

此解决方案将仅防止从 Java 字符串池中读取密码。无论如何,这是一种非常罕见的攻击方式。 Ans 密码以纯文本形式传输。

我的建议是,您应该使用密码学的一些好处,而不是使数据库架构复杂化。不传递密码值,您应该传递password digest

摘要函数的简单示例。

public static String getDigest(byte[] password) {

  return new String(Hex.encodeHex(new MessageDigest.getInstance("SHA").digest(password)));

}

然后将摘要存储在 db 中是安全的,并在查询中使用简单字符串。

【讨论】:

    【解决方案3】:

    看看这段代码

    final PreparedStatement statement = connection.prepareStatement(
            "SELECT my_column FROM my_table " + 
            "where search_column IN (SELECT * FROM unnest(?))"
    );
    final String[] values = getValues();
    statement.setArray(1, connection.createArrayOf("text", values));
    final ResultSet rs = statement.executeQuery();
    try {
        while(rs.next()) {
            // do some...
        }
    } finally {
        rs.close();
    }
    

    也请看这篇文章以供参考http://people.apache.org/~djd/derby/publishedapi/java/sql/PreparedStatement.html

    【讨论】:

    • 使用字符串,我希望避免使用字符串。可以使用char 的数组吗?
    【解决方案4】:

    另一种选择是使用CharArrayReader 并调用statement.setCharacterStream

    char[] passwordString = new char[] { 't', 'e', 's', 't' };
    statement.setCharacterStream(1, new CharArrayReader(passwordString));
    

    【讨论】:

    • 这种方法适合插入明文密码吗?
    • 理论上是的。只需确保将引用设置为 null 以将对象标记为集合的候选对象
    猜你喜欢
    • 2020-09-29
    • 2023-02-01
    • 2016-10-25
    • 1970-01-01
    • 2022-08-22
    • 1970-01-01
    • 1970-01-01
    • 2012-09-26
    • 1970-01-01
    相关资源
    最近更新 更多