Frage

Sprich: Sie sind ein Formular abzuschicken, die Ihre Datenbank (Hinzufügen von Datensätzen / löschen sie / Aktualisierung sie), und dies ist, wie Sie Ihre Anfrage sieht aus wie wirkt sich:

POST / application / action = update

Nun, sagen wir, Sie sind mit Ihrem Update durchgeführt, so dass Sie den Benutzer auf die Homepage nehmen möchten.

response.sendRedirect / application / action = home

Das funktioniert wunderbar gut. Benutzer wird eine Umleitung nach dem POST, gesendet, so auch wenn der Benutzer die Seite zu aktualisieren versucht, von F5 schlagen, sind Sie gut. Dies wird jedoch nicht funktionieren, wenn Sie das getan haben:

RequestDispatcher.forward (/ application / action = home)

Da es ein Szenario, wo man verschiedene Arten von Fehler- / Erfolgsmeldungen angezeigt werden, nachdem Sie mit Ihrem Update fertig sind, werden Sie höchstwahrscheinlich ein vorwärts nach dem POST zu tun. In einem solchen Szenario, wie vermeiden Sie Update-Aktionen von zweimal passiert?

Ich finde es eher amüsant, dass viele sicheren Seiten (Bänke) / Zahlungs-Gateways sind in der Regel um den Benutzer zu informieren, indem Text auf dem Bildschirm platzieren, wie „Bitte drücken Sie nicht zurück / Refresh-Buttons“.

Gibt es keinen besseren Weg, dies zu umgehen? Anders als die Benutzer auffordert, nicht diese Tasten drücken? Als ich das letzte Mal überprüft, war es etwas das ‚Vertical Response Cache‘ genannt. Ein Filter, die Einzigartigkeit Ihrer Anfrage in einer Sitzung identifizieren würden und versucht, eine zwischengespeicherte Antwort zu senden, wenn die Anforderung Duplikat ist. Gibt es einfachere Möglichkeiten, dieses klassische Problem zu lösen?

Hier ist ein Link auf die vertikale Reaktion Cache Lösung, die ich sprach: http: / /www.fingo.info/en/articles/_1.html . Ich bin jedoch nicht sicher, wie gut das wirklich funktioniert.

War es hilfreich?

Lösung

Ein Gedanke, den ich habe habe, ist eine eindeutige ID einbetten (wahrscheinlich eine zufällige Zeichenfolge) als verstecktes Formularfeld in der Form, die POST-abgegeben wird. Der ID-String kann in der Datenbank als „Transaktions-ID“ gesetzt werden. Wenn Sie nun die Datenbank aktualisieren gehen, zunächst zu prüfen, ob es eine bestehende Datensatz mit der Transaktions-ID vorgelegt, und wenn ja, nähme an, es ist ein Duplikat und die Datenbank nicht ändern.

Natürlich, wie gesagt, das ist nur ein Gedanke. Ich weiß nicht, welche Methoden tatsächlich in der Praxis eingesetzt werden. (Ich vermute, dass eine Menge von weniger kritischen Stellen einfach ignoriert das Problem und hofft, dass ihre Benutzer intelligent sein ... ein Verlustgeschäft, wenn ich je gesehen habe; -)

EDIT : wie in den Kommentaren darauf hingewiesen, Transaktions-IDs in der Datenbank gespeichert werden könnten viel Platz in Anspruch nehmen, aber wenn das ein Problem ist, könnten Sie einen In-Memory-Cache aller Transaktion halten in den letzten 5 Minuten verarbeitet IDs / 1 Stunde / 1 Tag / was auch immer. Das sollte funktionieren, wenn Sie gegen einen bestimmten Hacker ...

Andere Tipps

Ja, ich glaube, dass Sie nach einer POST, mit Ausnahme von API-Anforderungen umleiten sollen. Ohne dies zu tun Sie nicht nur darum, doppelte Veröffentlichungen kümmern, wenn der Benutzer die Zurück-Taste verwendet, aber der Browser dem Benutzer auch lästige Dialoge geben, wenn sie versuchen, die Zurück-Taste zu verwenden.

response.sendRedirect in der Praxis funktioniert, aber tecnically dies spricht ist die falsche HTTP-Response-Code für diesen Zweck sendet. sendRedirect sendet ein 302, aber der richtige Code zu verwenden, um eine POST in eine GET zu transformieren ist 303. (die meisten Browser ein 302 behandeln wie ein 303, wenn sie es in Reaktion auf einen POST erhalten, jedoch)

In der Regel wollen Sie die Umleitung, um den Benutzer zu senden, was auch immer Sicht wird die Wirkung ihrer Änderung anzuzeigen. Zum Beispiel, wenn sie ein Widget bearbeiten, sollten sie zu der Ansicht, dieses Widget weitergeleitet. Wenn sie ein Widget löschen, sollen sie zu der Ansicht umgeleitet werden, dass das Widget in erschienen wäre, wenn es existiert (vielleicht die Widget-Liste).

Manchmal ist es schön, eine Statusnachricht haben zu Hause der Tatsache weiter zu treiben, dass eine Aktion aufgetreten. Ein einfacher Weg, dies zu tun, ist einen gemeinsamen Parameter zu Ihren Ansichten zu haben, das, wenn sie gesetzt ist, wird eine Aktion abgeschlossen Nachricht angezeigt werden soll. zB:

/widget?id=12345&msg=Widget+modified.

Hier ist der "msg" Parameter die Meldung "Widget geändert" enthält. Der einzige Nachteil dieses Ansatzes besteht darin, dass es möglich sein kann, für bösartige Websites die Benutzer verwirrend / irreführende Nachrichten zu geben. zB:

/account?msg=Foo+Corp.+hates+you.

Wenn Sie wirklich darüber besorgt könnten Sie eine auslaufende Signatur für die Nachricht als zusätzliche Parameter umfassen. Wenn die Signatur ungültig oder abgelaufen ist, einfach nicht die Meldung angezeigt werden soll.

Die beste Lösung, das Problem der zeigt Statusmeldungen an den Benutzer nach einer POST zu lösen umleiten zu bekommen, ist Benutzersitzungen zu verwenden.

Wie

Fügen Sie Attribute Benutzersitzung mit dem Wert als Satz von Nachrichten angezeigt werden. für zB.

userSession.put("success_messages", new HashSet<String>(){"Success", "Check your account balance"});
userSession.put("warning_messages", new HashSet<String>(){"Your account balance is low. Recharge immediately"});

Und haben einen Filter, der die Benutzersitzung für diese bestimmten Attribute durchsucht und gibt die Nachrichten. Der Filter soll die Attribute nach dem Lesen einmal löschen, da die Statusmeldungen der Regel nur einmal angezeigt werden.

Ich finde es eher amüsant, dass viele sicheren Seiten (Bänke) / Zahlungs-Gateways sind in der Regel um den Benutzer zu informieren, indem Text auf dem Bildschirm platzieren, wie „Bitte drücken Sie nicht zurück / Refresh-Buttons“.

einige Leute finden es besser, „All deaktivieren Back, Refresh-Ereignis auf diesen kritischen Seiten“; Ich bin mir nicht sicher, ob das gut ist oder nicht.

Aber Ihre adressierte Lösung " vertikale Reaktion Cache " klingt schön

Es ist ein wenig nicht offensichtlich, aber:

  • erstellen verkeilt-Objekt in der Benutzersitzung.
  • der Wert ein Request + Java-Zukunft für das Ergebnis
  • Rückkehr sofort mit einer clientseitige Umleitung.
  • , während der Client-Seite Umleitung auf die Herstellung der Antwort ein Worker-Thread Arbeit haben gehandhabt wird.

Also von der Zeit der Client-Browser die Umleitung abgeschlossen ist, die neue Seite Bilder bekommen, etc ... die Ergebnisse für den Benutzer warten.

Die Alternative ist der Benutzer schmerzlich bewusst, wie lange die Datenbank zu machen nimmt.

Sicherheitsupdate (2011 24. Januar):

Der Schlüssel ist angreifbar, da sie Teil der Antwort an den Client, so

ist
  1. Erstellen Sie einen zufälligen Schlüssel
  2. Verwenden Sie Benutzer-Session-ID als Salz ein SHA-1
  3. erstellen
  4. Speicher sowohl der Zufallsschlüssel und die SHA-1 in der Datenbank mit (,) als der Primärschlüssel. (Keine separate Indizierung auf dem RANDOMKEY.
  5. Verwenden Sie beide RANDOMKEY und den SHA-1 als db-Lookup.
  6. Speichern Sie nicht die Session-ID (Datenschutzprobleme vermeiden mit vielen Einträgen auf den gleichen Benutzer corollate zu können)
  7. Ablaufen der Ergebnisse nach 2-3 Tagen. (Ermöglicht einen täglichen Batch-Job die sauber und vermeidet Probleme schaffen für Benutzersitzungen zu tun, das sind halb langlebig)

Diese Methode erfordert jeden Hacker sowohl die Session-ID und die zufälligen Schlüssel zu kennen.

Dieser Ansatz kann übertrieben erscheinen, aber eine Umleitung gehärteten Mechanismus kann für Situationen wie das Zurücksetzen von Kennwörtern verwendet werden.

Wenn Sie mit Java-Server-Side-Scripting arbeiten und auch Streben mit 2 dann verweisen Sie auf diesen Link, die etwa zur Verwendung eines Token spricht.

http://www.xinotes.org/notes/note/369/

Es sollte ein Token in der Sitzung für die erste Seite übertragen, erzeugt und gehalten werden, wenn der Antrag zusammen mit dem Token zum ersten Mal vorgelegt wird, Aktion in Streben ein Gewinde mit Gewinden Namen wie das Token-ID laufen und die Logik läuft unabhängig der Kunde hat beantragt, wenn der Client erneut über den gleichen Antrag prüfen, ob der Thread noch läuft (thread.getcurrentthread (). unterbrochen), wenn dann noch ein Client 503 ausgeführt wird senden umleiten.

Bitte schauen auf dem ExecuteAndWaitInterceptor Streben 2code, die Logik dieses mit Token kombiniert wird schnellen Klick helfen

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top