Sicheres Data Binding im Play Framework

CTO Post For Happy Coding

Sicheres Data Binding im Play Framework - Post des insign CTOs Martin Bachmann

Ausgangslage

Mit dem Play Framework lassen sich Formular-Übermittlungen elegant im zugrunde liegenden Datenmodell speichern. Dazu wird ein Form-Objekt aus dem eingehenden Request erstellt, daraus die Entity geholt und gespeichert, wie im nachfolgenden Beispiel (aus der Play-Beispiel App „Computer Database“) gezeigt.

/**
 * Handle the 'new computer form' submission
 */
public static Result save() {
    Form<Computer> computerForm = form(Computer.class).bindFromRequest();
    if(computerForm.hasErrors()) {
        return badRequest(createForm.render(computerForm));
    }
    computerForm.get().save();
    return GO_HOME;
}

Das Problem

Auf den ersten Blick mag man versucht sein – wie im von Play mitgelieferten Beispiel auch suggeriert – direkt seine Modelle so zu aktualisieren. Dies führt aber natürlich zu einem grossen Sicherheitsloch: Das Mapping von Formularfeld zu Entity-Attribut erfolgt automatisch anhand des Namens. Durch Veränderung der GET/POST-Daten (Parameter Tampering) kann der Angreifer jedes beliebige Feld der hinterlegten Entität verändern, auch wenn er per Formular darauf keinen Zugriff hätte.

Übliche Lösungen

Man erstellt eine für jedes Formular spezifische Formular-Klasse, welche die erlaubten Felder definiert und das Mapping auf die Model-Klasse übernimmt. Oder man verwendet den allowedFields Parameter in bindFromRequest() um die erlaubten Felder einzuschränken.

Beide Methoden erfordern, dass die editierbaren Felder explizit doppelt definiert werden: Im Formular sowie in der Form-Klasse (oder dem allowedFields Parameter). Das kann bei umfangreichen und oft ändernden Formularen recht umständlich und fehleranfällig werden. Auch, weil standardmässig nicht erkannte Felder still ignoriert werden – was beim Debugging nicht gerade hilfreich ist.

Die SecureForm

Wir haben mit dem SecureForm Projekt einen weiteren Ansatz für das Play Framework implementiert und veröffentlicht. Hierbei wird das Formular mit einer Formular-Signatur gegen Parameter Tampering gesichert. Die Felder, welche im Formular vorhanden sind, wenn dieses zum Client geschickt wird, werden gelistet und signiert (SHA256 Hash über Formularfeldliste und den Play-eigenen, app-spezifischen application.secret Config-Wert, den Play auch für die Signierung der Session verwendet). Beim Empfang des Formulars werden die erhaltenen Daten gegen Liste und Hash geprüft, bei Unstimmigkeiten wird ein Fehler generiert.

So setzen Sie SecureForms ein:

1. Den @formKey Template-Helper ins Formular einfügen

2. Das Formular bei Ausgabe signieren:

public static Result edit(Long id) {
    Form<Computer> computerForm = form(Computer.class).fill(
            Computer.find.byId(id)
    );

    return ok(

        /** Computes and adds the formKey from the rendered html forms **/
        SecureForm.signForms(
            editForm.render(id, computerForm)
        )
    );
}

3. SecureForm anstelle von Form verwenden um Formulareingänge ans Model zu binden:

/**
 * Handle the 'edit form' submission
 *
 * @param id Id of the computer to edit
 */
public static Result update(Long id) {

    // Note: You could also use Play's allowedFields param - this would
    // silently ignore sent but not allowed fields:
    // String allowedFields[] = {"name", "company.id", "introduced", ..};
    // Form<Computer> computerForm = SecureForm.form(Computer.class)
    //     .bindFromRequest(allowedFields);

    Form<Computer> computerForm = SecureForm.form(Computer.class)
        .bindFromRequest();

    if(computerForm.hasErrors()) {
        return badRequest(
            SecureForm.signForms(
                editForm.render(id, computerForm)
            )
        );
    }

    computerForm.get().update(id);
    return GO_HOME;
}

Details zum Projekt finden Sie hier: https://bitbucket.org/bachi76/play2-secureform (es handelt sich hierbei um das mit Play mitgelieferte Computer Database Beispiel, wobei zu Demozwecken das Hinzufügen von Einträgen ungesichert und das Editieren gesichert wurde).

Happy coding.

Links in diesem Kontext

playframework.com
Secure Form Project auf bitbucket.org
Parameter Tempering auf owasp.org

Von Martin BachmannMartin Bachmann auf FacebookMartin Bachmann auf Google+Martin Bachmann auf Twitter Autoren-Webseite anschauen

Mitgründer und CTO @insigngmbh, Initiant von @android_schweiz, Android Evangelist und jetzt auch Papi.

Kommentare (0)

Kommentar verfassen