18.11 PGQL問合せを実行するためのセキュリティ・ツール
問合せインジェクションから保護するために、リテラルのかわりにバインド変数を使用し、グラフ名、ラベル、プロパティ名などの識別子のかわりにprintIdentifier(String identifier)
を使用できます。
- バインド変数の使用
バインド変数を使用する理由は2つあります。 - 安全な方法での識別子の使用
文字列の連結を介して問合せを作成すると、問合せのリテラルのみでなく、グラフ名、ラベル、プロパティ名などの識別子でもセキュリティ上のリスクが生じます。唯一の問題は、バインド変数がそのような識別子でサポートされていないことです。したがって、これらの識別子がアプリケーションの観点から可変である場合は、oracle.pgql.lang.ir.PgqlUtils.printIdentifier(String identifier)
メソッドを介して識別子を渡すことにより、問合せインジェクションから保護することをお薦めします。
親トピック: グラフ・サーバー(PGX)に対するPGQL問合せの実行
18.11.1 バインド変数の使用
バインド変数を使用する理由は2つあります。
- 問合せインジェクションから保護します。
- 問合せの再コンパイルを必要とせずに同じバインド変数を複数回設定できるため、問合せの実行が高速化されます。
プリペアド文を作成するには、次の2つの方法のいずれかを使用します。
PgxGraph.preparePgql(String query) : PgxPreparedStatement
PgxSession.preparePgql(String query) : PgxPreparedStatement
これらのメソッドから返されるPgxPreparedStatement (package oracle.pgx.api)
には、バインド変数を指定されたデータ型の値にバインドするためのsetterメソッドがあります。
PreparedStatement stmnt = g.preparePgql(
"SELECT v.id, v.dob " +
"FROM MATCH (v) " +
"WHERE v.firstName = ? AND v.lastName = ?");
stmnt.setString(1, "Camille");
stmnt.setString(2, "Mullins");
ResultSet rs = stmnt.executeQuery();
問合せ内の各バインド変数は、PgxPreparedStatement
の次のセッターのいずれかを使用して値に設定する必要があります。
setBoolean(int parameterIndex, boolean x)
setDouble(int parameterIndex, double x)
setFloat(int parameterIndex, float x)
setInt(int parameterIndex, int x)
setLong(int parameterIndex, long x)
setDate(int parameterIndex, LocalDate x)
setTime(int parameterIndex, LocalTime x)
setTimestamp(int parameterIndex, LocalDateTime x)
setTimeWithTimezone(int parameterIndex, OffsetTime x)
setTimestampWithTimezone(int parameterIndex, OffsetDateTime x)
setArray(int parameterIndex, List<?> x)
すべてのバインド変数が設定されると、文は次の方法で実行できます。
PgxPreparedStatement.executeQuery()
SELECT
問合せの場合のみ- ResultSetを返します
PgxPreparedStatement.execute()
- あらゆるタイプの文の場合
- 結果の形式を示すブール値を返します。
SELECT
問合せの場合はtrue、それ以外の場合はfalseです。 SELECT
の場合、ResultSetには後でPgxPreparedStatement.getResultSet()
を使用してアクセスできます。
PGQLでは、配列リテラルを含む任意のデータ型のリテラルのかわりにバインド変数を使用できます。文字列配列のインスタンスにバインド変数が設定されている問合せの例は次のとおりです。
List<String> countryNames = new ArrayList<String>();
countryNames.add("Scotland");
countryNames.add("Tanzania");
countryNames.add("Serbia");
PreparedStatement stmnt = g.preparePgql(
"SELECT n.name, n.population " +
"FROM MATCH (c:Country) " +
"WHERE c.name IN ?");
ResultSet rs = stmnt.executeQuery();
最後に、プリペアド文が不要になった場合は、PgxPreparedStatement.close()
を介してクローズされ、リソースが解放されます。
親トピック: PGQL問合せを実行するためのセキュリティ・ツール
18.11.2 安全な方法での識別子の使用
文字列の連結を介して問合せを作成すると、問合せのリテラルのみでなく、グラフ名、ラベル、プロパティ名などの識別子でもセキュリティ上のリスクが生じます。唯一の問題は、バインド変数がそのような識別子でサポートされていないことです。したがって、これらの識別子がアプリケーションの観点から可変である場合は、oracle.pgql.lang.ir.PgqlUtils.printIdentifier(String identifier)
メソッドを介して識別子を渡すことにより、問合せインジェクションから保護することをお薦めします。
識別子文字列を指定すると、メソッドは識別子の先頭と末尾に二重引用符を自動的に追加し、識別子内の文字を適切にエスケープします。
次のケースについて検討します。
String graphNamePrinted = printIdentifier("my graph name with \" special % characters ");
PreparedStatement stmnt = g.preparePgql(
"SELECT COUNT(*) AS numVertices FROM MATCH (v) ON " + graphNamePrinted);
親トピック: PGQL問合せを実行するためのセキュリティ・ツール