Ich möchte doppelte Submission Prevention in einer bestehenden Java Web Application implementieren (struts tatsächlich). Architektonisch sprechen wir von 2 bis N möglichen Anwendungsservern (tomcat) und einem einzigen Datenbankserver (mysql). Die einzelnen Server kennen sich nicht und können keine Nachrichten austauschen. Vor den Anwendungsservern gibt es einen einzelnen Load Balancer, der sticky sessions ausführen kann.
Grundsätzlich gibt es also zwei Arten von Double-Submission-Prevention-Client-Seite und Server-Seite. Wenn möglich, möchte ich auf die Serverseite gehen, da alle clientseitigen Techniken scheitern, wenn die Leute Cookies und / oder Javascript in ihren Browsern deaktivieren.
Das bringt mich auf die Idee, eine Art Mutex-ähnliche Synchronisation über Datenbanksperren durchzuführen. Ich denke, es ist möglich, eine Prüfsumme der vom Benutzer eingegebenen Daten zu berechnen und sie in einer dedizierten Datenbanktabelle zu speichern. Bei jedem Antrag muss der Antrag auf Vorhandensein einer gleichen Prüfsumme prüfen, die anzeigen würde, dass die gegebene Einreichung ein Duplikat ist. Natürlich müssen die Prüfsummen in dieser Tabelle regelmäßig gelöscht werden. Das Problem ist der ganze Prozess der Überprüfung, ob es bereits eine doppelte Prüfsumme in der Datenbank gibt und das Einfügen der Prüfsumme, wenn es keine gibt, ist ein kritischer Abschnitt . Daher muss die Checksum-Tabelle vorher gesperrt und nach dem Abschnitt wieder entsperrt werden.
Mein Deadlock und Flaschenhals Alarmglocken beginnen zu klingeln, wenn ich über Tischschlösser nachdenke. Meine Frage ist also: Gibt es bessere Möglichkeiten, doppelte Übergaben in staatenlosen Webanwendungen zu verhindern?
Bitte beachten Sie, dass die Struts TokenInterceptor
hier nicht angewendet werden können, weil sie es sind scheitert kläglich, wenn Cookies deaktiviert werden (es beruht auf der HTTP-Sitzung, die ohne Sitzungscookies einfach nicht vorhanden ist).
Eine einfachere DB-basierte Lösung wäre ungefähr so. Dies kann auch für mehrere Formulare generisch gemacht werden.
Die klassische Technik zur Vermeidung von doppelten Eingaben besteht darin, zwei IDs (beide als "verstecktes" Feld im HTML-Formular-Tag) zuzuweisen - eine "Sitzungs-ID", die von der Anmeldung bis zur Abmeldung gleich bleibt ...
Die zweite ID ändert sich mit jeder Eingabe ... serverseitig müssen Sie nur die "aktuell gültige ID" (sitzungsspezifisch) nachverfolgen ... wenn Sie eine "erneute Eingabe" erhalten (per Klick) happy-user oder ein "Refresh-Button" oder ein "Zurück-Button" oder ...) dann würde das nicht mit der aktuellen ID übereinstimmen ... auf diese Weise wisst ihr: Diese Submission sollte verworfen werden und eine neue ID generiert werden und schickte mit der Antwort zurück. Einige Implementierungen verwenden eine ID, die bei jeder Einreichung inkorporiert wird, was den Check / Kepp-Track-Teil etwas vereinfacht, aber anfällig für "Raten" ist (Sicherheitsbedenken) ... Ich möchte kryptografisch starke IDs für diese Art von Schutz erstellen ...
Wenn Sie eine Load-Balanced-Umgebung mit sticky-Sitzung haben, dann müssen Sie nur die ID auf dem Server selbst (in-memory) verfolgen ... aber Sie können sicherlich die ID in der DB speichern ... da Sie speichern es zusammen mit der Sitzungs-ID, die Sperre wäre auf "Zeilenebene" (nicht auf Tabellenebene), was in Ordnung sein sollte.
Die von Ihnen beschriebene Vorgehensweise geht noch einen Schritt weiter, indem Sie den Inhalt untersuchen ... ABER ich sehe den Inhalt mehr auf der "Anwendungslogik" -Ebene als auf der "Wiedervorlage-Verhinderungsstufe", da es von der App-Logik abhängt es will die gleichen Daten wieder aufnehmen ...
Was ist, wenn Sie mit sticky sessions arbeiten, dann wären Sie mit TokenManagement in Ordnung. Es gibt eine DoubleClickFilter
, die du deinem web.xml
hinzufügen kannst.
Da Sie Sticky-Sitzungen haben, brauchen Sie keine Cross-Tomcat-Lösung.
Tags und Links java web-applications double-submit-prevention struts stateless