396 Stimmen

PreparedStatement IN-Klausel Alternativen?

Was sind die besten Umgehungsmöglichkeiten für die Verwendung eines SQL IN Klausel mit Instanzen von java.sql.PreparedStatement die aufgrund von Sicherheitsproblemen bei SQL-Injection-Angriffen für mehrere Werte nicht unterstützt wird: Eine ? Platzhalter steht für einen Wert und nicht für eine Liste von Werten.

Betrachten Sie die folgende SQL-Anweisung:

SELECT my_column FROM my_table where search_column IN (?)

Verwendung von preparedStatement.setString( 1, "'A', 'B', 'C'" ); ist im Wesentlichen ein nicht funktionierender Versuch einer Umgehung der Gründe für die Verwendung von ? an erster Stelle.

Welche Umgehungsmöglichkeiten gibt es?

1voto

stjohnroe Punkte 3108

Versuchen Sie es mit der Funktion instr?

select my_column from my_table where  instr(?, ','||search_column||',') > 0

dann

ps.setString(1, ",A,B,C,"); 

Zugegebenermaßen ist dies ein etwas schmutziger Hack, aber er reduziert die Möglichkeiten für Sql-Injection. Funktioniert in Oracle sowieso.

0voto

pedram bashiri Punkte 1106

PreparedStatement bietet keine gute Möglichkeit, mit der SQL IN-Klausel umzugehen. Per http://www.javaranch.com/journal/200510/Journal200510.jsp#a2 "Sie können keine Dinge ersetzen, die Teil der SQL-Anweisung werden sollen. Das ist notwendig, denn wenn sich die SQL-Anweisung selbst ändern kann, kann der Treiber die Anweisung nicht vorkompilieren. Außerdem hat dies den angenehmen Nebeneffekt, dass SQL-Injection-Angriffe verhindert werden." Am Ende habe ich folgenden Ansatz gewählt:

String query = "SELECT my_column FROM my_table where search_column IN ($searchColumns)";
query = query.replace("$searchColumns", "'A', 'B', 'C'");
Statement stmt = connection.createStatement();
boolean hasResults = stmt.execute(query);
do {
    if (hasResults)
        return stmt.getResultSet();

    hasResults = stmt.getMoreResults();

} while (hasResults || stmt.getUpdateCount() != -1);

0voto

Rod Meyer Punkte 498

OK, ich konnte mich nicht genau daran erinnern, wie (oder wo) ich das vorher gemacht habe, also bin ich zu Stack Overflow gegangen, um schnell die Antwort zu finden. Ich war überrascht, dass ich es nicht konnte.

So habe ich das IN-Problem vor langer Zeit mit einer Aussage wie dieser umgangen:

where myColumn in ( select regexp_substr(:myList,'[^,]+', 1, level) from dual connect by regexp_substr(:myList, '[^,]+', 1, level) is not null)

den Parameter myList als kommagetrennte Zeichenfolge festlegen: A,B,C,D...

Hinweis: Sie müssen den Parameter zweimal einstellen!

0voto

epeleg Punkte 9853

Nur der Vollständigkeit halber und weil ich nicht gesehen habe, dass jemand anderes es vorgeschlagen hat:

Bevor Sie einen der oben genannten komplizierten Vorschläge umsetzen, sollten Sie prüfen, ob SQL-Injection in Ihrem Szenario tatsächlich ein Problem darstellt.

In vielen Fällen ist der an IN (...) übergebene Wert eine Liste von IDs, die so generiert wurden, dass Sie sicher sein können, dass keine Injektion möglich ist (z. B. die Ergebnisse eines vorherigen select some_id from some_table where some_condition).

Wenn das der Fall ist, können Sie diesen Wert einfach verketten und die Dienste oder die vorbereitete Anweisung nicht dafür verwenden oder sie für andere Parameter dieser Abfrage verwenden.

query="select f1,f2 from t1 where f3=? and f2 in (" + sListOfIds + ");";

0voto

bnsk Punkte 131

Nachdem ich verschiedene Lösungen in verschiedenen Foren untersucht und keine gute Lösung gefunden habe, denke ich, dass der folgende Hack, den ich mir ausgedacht habe, am einfachsten zu befolgen und zu codieren ist:

Beispiel: Angenommen, Sie haben mehrere Parameter, die Sie in der 'IN'-Klausel übergeben müssen. Fügen Sie einfach einen Dummy-String in die 'IN'-Klausel ein, z. B. "PARAM", um die Liste der Parameter zu bezeichnen, die anstelle dieses Dummy-Strings übergeben werden sollen.

    select * from TABLE_A where ATTR IN (PARAM);

Sie können alle Parameter in einer einzigen String-Variablen in Ihrem Java-Code zusammenfassen. Dies kann wie folgt geschehen:

    String param1 = "X";
    String param2 = "Y";
    String param1 = param1.append(",").append(param2);

Sie können alle Ihre Parameter durch Kommas getrennt in einer einzigen String-Variablen anhängen, in unserem Fall 'param1'.

Nachdem Sie alle Parameter in einer einzigen Zeichenkette zusammengefasst haben, können Sie einfach den Blindtext in Ihrer Abfrage, d. h. in diesem Fall "PARAM", durch die Parameterzeichenkette, d. h. param1, ersetzen. So müssen Sie vorgehen:

    String query = query.replaceFirst("PARAM",param1); where we have the value of query as 

    query = "select * from TABLE_A where ATTR IN (PARAM)";

Sie können nun Ihre Abfrage mit der Methode executeQuery() ausführen. Achten Sie nur darauf, dass das Wort "PARAM" nirgendwo in Ihrer Abfrage vorkommt. Sie können anstelle des Wortes "PARAM" eine Kombination von Sonderzeichen und Alphabeten verwenden, um sicherzustellen, dass ein solches Wort in der Abfrage nicht vorkommen kann. Ich hoffe, Sie haben die Lösung gefunden.

Hinweis: Obwohl es sich hierbei nicht um eine vorbereitete Abfrage handelt, erledigt sie die Arbeit, die ich mit meinem Code erledigen wollte.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X