2

データベースを 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())、returnType の最初のフィールド (userId) のみが ResultSet に表示されます。

ストアドプロシージャをそのまま呼び出す場合:

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) を実装しました。アプリケーションはローカル ネットワークで実行されます。SQL インジェクション攻撃 (コメント --、セミコロン、*、および DELETE などの他の SQL コマンド) を回避するために、さまざまな Java Swing コンポーネントからのユーザー入力を検証しています。

どんな入力でも大歓迎です。

ありがとう。

4

1 に答える 1

1

まず、PostgreSQL はこのコマンドをサポートしていないためcall、最初のアプローチは失敗します。

2 番目のアプローチでは、2 つの問題が発生します。1 つ目は SQL インジェクションです。標準のバインディングアプローチを使用すると、それが修正されます。2 番目の問題は、関数を呼び出したときに関数からデータを解析するのが難しくなることです。

より良いアプローチは次のようなものになります

SELECT * FROM user_login_get_id_password(?)

ただし、関数内で SQL インジェクションが可能であることに注意してください。 回避できる範囲で、それがあなたEXECUTEを守ります。execute を使用する必要がある場合は、クエリ文字列を次のように変更します。

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

実行クエリ内の終了セミコロンは必要ありません。自動的に終了します。ただし、quote_literal を呼び出す必要があります (テーブル/列名を引用する場合は quote_ident() を使用します)。

于 2013-04-04T13:26:49.660 に答える