2016-04-01 27 views
4

Ich möchte eine JDBI-Abfrage dynamisch filtern.JDBI Wie kann ich dynamisch eine WHERE-Klausel erstellen, während SQL Injection verhindert wird?

Die Liste der Parameter wird von der Benutzeroberfläche über REST übergeben, z.

http://localhost/things?foo=bar&baz=taz 
http://localhost/things?foo=buz 

Welche (plump) gebaut (Jersey @Context UriInfo :: getQueryParameters -> String) so etwas wie folgt aus:

WHERE foo=bar AND baz=taz 

Und JDBI geleitet, die wie folgt aussieht:

@UseStringTemplate3StatementLocator 
public interface ThingDAO { 
    @SqlQuery("SELECT * FROM things <where>) 
    List<Thing> findThingsWhere(@Define("where") String where); 
} 

Soweit ich verstehe, ist die aktuelle Implementierung anfällig für SQL-Injektion. Ich kann offensichtlich die Spaltennamen, aber nicht die Werte bereinigen. 1

Es muss eine elegantere und SQL-Injection-sichere Möglichkeit geben, dies zu tun.

+0

Ich glaube nicht, hat er die Liste von Parametern des Typs 'Long' (die nicht in der Lage sein sollte, für die Injektion wizardry verwendet werden;)) und' @ BindIn' scheint PreparedStatements zu verwenden welches '@ Define' (so weit ich es verstanden habe) nicht. – unSinn

Antwort

1

Inspiriert von Jean-Bernard kam ich mit auf den Punkt:

public class WhereClause { 
    public HashMap<String, String> queryValues; // [<"foo","bar">, <"baz","taz">] 
    public String preparedString; // "WHERE foo=:foo AND bar=:baz" 
} 

, die über eine benutzerdefinierte Binder BindWhereClause gebunden ist:

@BindingAnnotation(BindWhereClause.WhereClauseBinderFactory.class) 
@Retention(RetentionPolicy.RUNTIME) 
@Target({ElementType.PARAMETER}) 
public @interface BindWhereClause { 
    class WhereClauseBinderFactory implements BinderFactory { 
     public Binder build(Annotation annotation) { 
      return new Binder<BindWhereClause, WhereClause>() { 
       public void bind(SQLStatement q, BindWhereClause bind, WhereClause clause) { 
        clause.queryValues 
          .keySet() 
          .forEach(s -> q.bind(s, clause.queryValues.get(s))); 
       } 
      }; 
     } 
    } 
} 

und eine Kombination aus @Define und @Bind:

@UseStringTemplate3StatementLocator 
public interface ThingDAO { 
    @SqlQuery("SELECT * FROM things <where>) 
    List<Thing> findThingsWhere(@Define("where") String where, 
           @BindWhereClause() WhereClause whereClause); 
} 

Dies sollte spritzwassergeschützt sein. (Ist es?)

+0

Woher kommen Ihre 'queryValues'-Schlüssel? Wenn vom Kunden, dann sind Sie immer noch anfällig für die Injektion. z.B. "Foo; Drop Tisch Studenten; -". Sehen Sie sich auch die Annotation '@ BindIn' in JDBI an - sie kombiniert sowohl die Definition als auch die Bindungen in einer einzigen Annotation. Es könnte Ihre Verwendung vereinfachen. – qualidafial

+0

ist die preparedString nie irgendwo hier verwendet? Wie würdest du die Methode "findThingsWhere" nennen? Wie liefert man hier Params? –

0

Verwenden Sie eine parametrisierte Abfrage. Here ist die jdbi Seite für sie.
Mit parametrisierten Abfragen können Sie die SQL-Injektion in den meisten Einstellungen verhindern.

Sie können die where-Anweisung dynamisch erstellen, aber Parameternamen anstelle von Werten lassen, sie werden später auf sichere Weise gebunden.

Sie würden wahrscheinlich in diesem Bit speziell interessiert sein, da Ihre Parameter dynamisch sind:

@BindingAnnotation(BindSomething.SomethingBinderFactory.class) 
@Retention(RetentionPolicy.RUNTIME) 
@Target({ElementType.PARAMETER}) 
public @interface BindSomething 
{ 

    public static class SomethingBinderFactory implements BinderFactory 
    { 
    public Binder build(Annotation annotation) 
    { 
     return new Binder<BindSomething, Something>() 
     { 
     public void bind(SQLStatement q, BindSomething bind, Something arg) 
     { 
      q.bind("ident", arg.getId()); 
      q.bind("nom", arg.getName()); 
     } 
     }; 
    } 
    } 
} 

Ich habe noch nie verwendet jdbi so bin ich nicht 100% sicher, was Sie tun müsste, aber Es sieht so aus, als ob die Methode q.bind (...) genau das ist, was Sie wollen.