Sicheres Data Binding im Play Framework

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.
[java light=”true” title=””]
/**
* 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;
}
[/java]
[devider type=”dots” /]

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.
[devider type=”dots” /]

Ü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.
[devider type=”dots” /]

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:
[java light=”true” title=””]
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)
)
);
}
[/java]
3. SecureForm anstelle von Form verwenden um Formulareingänge ans Model zu binden:
[java light=”true” title=””]
/**
* 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;
}
[/java]
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.
[devider type=”dots” /]
Links in diesem Kontext
[button url=”http://www.playframework.com” color=”green” size=”m” new_window=”1″ icon=”icon-arrow-right”]playframework.com[/button]
[button url=”https://bitbucket.org/bachi76/play2-secureform” color=”orange” size=”m” new_window=”1″ icon=”icon-arrow-right”]Secure Form Project auf bitbucket.org[/button]
[button url=”https://www.owasp.org/index.php/Web_Parameter_Tampering” color=”green” size=”m” new_window=”1″ icon=”icon-arrow-right”]Parameter Tempering auf owasp.org[/button]