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?

3voto

Hans-Peter Störr Punkte 24030

Der Frühling ermöglicht Übergabe von java.util.Lists an NamedParameterJdbcTemplate die die Erzeugung von (?, ?, ?, ?, ..., ?) entsprechend der Anzahl der Argumente automatisiert.

Für Oracle, dieser Blogeintrag diskutiert die Verwendung von oracle.sql.ARRAY (Connection.createArrayOf funktioniert nicht mit Oracle). Hierfür müssen Sie Ihre SQL-Anweisung ändern:

SELECT my_column FROM my_table where search_column IN (select COLUMN_VALUE from table(?))

Les Orakeltabellenfunktion wandelt das übergebene Array in einen tabellenartigen Wert um, der in der IN Erklärung.

3voto

Adam Bellaire Punkte 103525

Ich nehme an, Sie könnten (mit einfacher Stringmanipulation) den Abfrage-String in der PreparedStatement um eine Reihe von ? die mit der Anzahl der Einträge in Ihrer Liste übereinstimmen.

Wenn Sie das tun, sind Sie natürlich nur einen Schritt davon entfernt, eine riesige verkettete OR in Ihrer Abfrage, aber ohne die richtige Anzahl von ? in der Abfragezeichenfolge, weiß ich nicht, wie man das Problem sonst umgehen kann.

2voto

dwjohnston Punkte 9070

Hier ist eine vollständige Lösung in Java, um die vorbereitete Anweisung für Sie zu erstellen:

/*usage:

Util u = new Util(500); //500 items per bracket. 
String sqlBefore  = "select * from myTable where (";
List<Integer> values = new ArrayList<Integer>(Arrays.asList(1,2,4,5)); 
string sqlAfter = ") and foo = 'bar'"; 

PreparedStatement ps = u.prepareStatements(sqlBefore, values, sqlAfter, connection, "someId");
*/

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class Util {

    private int numValuesInClause;

    public Util(int numValuesInClause) {
        super();
        this.numValuesInClause = numValuesInClause;
    }

    public int getNumValuesInClause() {
        return numValuesInClause;
    }

    public void setNumValuesInClause(int numValuesInClause) {
        this.numValuesInClause = numValuesInClause;
    }

    /** Split a given list into a list of lists for the given size of numValuesInClause*/
    public List<List<Integer>> splitList(
            List<Integer> values) {

        List<List<Integer>> newList = new ArrayList<List<Integer>>(); 
        while (values.size() > numValuesInClause) {
            List<Integer> sublist = values.subList(0,numValuesInClause);
            List<Integer> values2 = values.subList(numValuesInClause, values.size());   
            values = values2; 

            newList.add( sublist);
        }
        newList.add(values);

        return newList;
    }

    /**
     * Generates a series of split out in clause statements. 
     * @param sqlBefore ""select * from dual where ("
     * @param values [1,2,3,4,5,6,7,8,9,10]
     * @param "sqlAfter ) and id = 5"
     * @return "select * from dual where (id in (1,2,3) or id in (4,5,6) or id in (7,8,9) or id in (10)"
     */
    public String genInClauseSql(String sqlBefore, List<Integer> values,
            String sqlAfter, String identifier) 
    {
        List<List<Integer>> newLists = splitList(values);
        String stmt = sqlBefore;

        /* now generate the in clause for each list */
        int j = 0; /* keep track of list:newLists index */
        for (List<Integer> list : newLists) {
            stmt = stmt + identifier +" in (";
            StringBuilder innerBuilder = new StringBuilder();

            for (int i = 0; i < list.size(); i++) {
                innerBuilder.append("?,");
            }

            String inClause = innerBuilder.deleteCharAt(
                    innerBuilder.length() - 1).toString();

            stmt = stmt + inClause;
            stmt = stmt + ")";

            if (++j < newLists.size()) {
                stmt = stmt + " OR ";
            }

        }

        stmt = stmt + sqlAfter;
        return stmt;
    }

    /**
     * Method to convert your SQL and a list of ID into a safe prepared
     * statements
     * 
     * @throws SQLException
     */
    public PreparedStatement prepareStatements(String sqlBefore,
            ArrayList<Integer> values, String sqlAfter, Connection c, String identifier)
            throws SQLException {

        /* First split our potentially big list into lots of lists */
        String stmt = genInClauseSql(sqlBefore, values, sqlAfter, identifier);
        PreparedStatement ps = c.prepareStatement(stmt);

        int i = 1;
        for (int val : values)
        {

            ps.setInt(i++, val);

        }
        return ps;

    }

}

1voto

Jeff Miller Punkte 1384

Sormula unterstützt den SQL IN-Operator, indem es Ihnen erlaubt, ein java.util.Collection-Objekt als Parameter zu übergeben. Es wird eine vorbereitete Anweisung mit einem ? für jedes der Elemente der Sammlung erstellt. Siehe Beispiel 4 (SQL im Beispiel ist ein Kommentar, um zu verdeutlichen, was erstellt wird, aber nicht von Sormula verwendet wird).

1voto

kapil das Punkte 1961

Statt mit

SELECT my_column FROM my_table where search_column IN (?)

verwenden Sie die Sql-Anweisung als

select id, name from users where id in (?, ?, ?)

et

preparedStatement.setString( 1, 'A');
preparedStatement.setString( 2,'B');
preparedStatement.setString( 3, 'C');

oder eine gespeicherte Prozedur zu verwenden, wäre die beste Lösung, da die SQL-Anweisungen kompiliert und im DataBase-Server gespeichert werden

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