我正在尝试保护我的数据库免受 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)。
任何意见都将受到欢迎。
谢谢。