【问题标题】:JDBC Postgres stored function call returning setof 'myType'JDBC Postgres 存储函数调用返回 setof 'myType'
【发布时间】:2012-06-30 17:01:09
【问题描述】:

我正在尝试保护我的数据库免受 SQL 注入。我有许多返回 SETOF 我预定义数据类型的存储函数。例如:

create type userLoginUserIdPasswordReturnType as
(
  userId integer, -- user.id
  password text 
);

CREATE OR REPLACE FUNCTION "user_login_get_id_password"(usernameIn text)
returns setof userLoginUserIdPasswordReturnType as
$$
declare
    sql text;
begin
      sql =  'select id, cryptpwd from "user" where username = ' || usernameIn ||';';
      return query execute sql;
end;
$$ language 'plpgsql';

我现在想从我的 Java 前端调用这些存储过程。根据我的阅读,就 SQL 注入而言,使用 CallableStatement 更安全。这是我迄今为止所拥有的:

public ArrayList<String> userLoginGetIdPassword(String username){
        ArrayList<String> result = new ArrayList<String>();
        try{
            String commandText = "{call user_login_get_id_password(?)}";
            this.cstmt = this.myConnection.prepareCall(commandText);
            this.cstmt.setObject(1, username);
//          this.rs = this.cstmt.execute();
            this.rs = cstmt.executeQuery();
            while (this.rs.next()){
                result.add(this.rs.getString(1));
            }
        } catch (SQLException e){
            System.out.println("SQL Exception: ");
            e.printStackTrace();
        }
        return result;
    }

如果我尝试使用 execute() 方法,它会要求我将 ResultSet rs 设置为布尔值。如果按原样运行 (executeQuery()),则在 ResultSet 中只能看到 returnType 的第一个字段 (userId)。

如果我这样调用存储过程:

public ArrayList<String> userLoginGetIdPassword(String username){
        ArrayList<String> result = new ArrayList<String>();
        try{
            String query = "select \"user_login_get_id_password\"('" + username + "');";
            System.out.println(query);
            this.stmt = this.myConnection.createStatement();
            this.rs = this.stmt.executeQuery(query);
            while (this.rs.next()){
                result.add(this.rs.getString(1));
            }
        } catch (SQLException e){
            System.out.println("SQL Exception: ");
            e.printStackTrace();
        }
        return result;
    }

我得到了正确的数据。

另外,如果有任何进一步的提示可以保护我的数据库免受 SQL 注入,请指出。我已经创建了应用程序将使用的特定 Postgres 角色,并实现了一个 ConnectionPool (c3p0) 来连接到我的数据库 - 应用程序将在本地网络上运行。我正在验证来自不同 Java Swing 组件的用户输入,以避免 SQL 注入攻击(注释 --、分号、* 和其他 SQL 命令,如 DELETE)。

欢迎任何意见。

谢谢。

【问题讨论】:

    标签: function postgresql jdbc callable


    【解决方案1】:

    首先,PostgreSQL 不支持 call 命令,这就是您的第一种方法失败的原因。

    在第二种方法中,您将遇到两个问题。首先是SQL注入。使用标准绑定方法将解决该问题。您的第二个问题是,您将很难从调用的函数中解析数据。

    更好的方法是

    SELECT * FROM user_login_get_id_password(?)
    

    但是请注意,sql 注入是可能的在你的函数内部。在一定程度上你可以避免EXECUTE 这将保护你。如果必须使用执行,请将查询字符串更改为:

    sql =  'select id, cryptpwd from "user" where username = ' || quote_literal(usernameIn);
    

    在执行查询中不需要结束分号。它会自动终止。不过,您确实需要调用 quote_literal(如果引用表/列名,请使用 quote_ident())。

    【讨论】:

      猜你喜欢
      • 2017-12-12
      • 1970-01-01
      • 2019-11-13
      • 1970-01-01
      • 1970-01-01
      • 2012-05-06
      • 2013-07-25
      • 1970-01-01
      • 2016-12-05
      相关资源
      最近更新 更多