Существуют ли методы для предотвращения двойного представления в веб-приложениях без сохранения состояния?
Я хочу реализовать двойное предотвращение отправки в существующем веб-приложении Java (фактически, Struts). В архитектуре мы говорим о 2 или N возможных серверах приложений (tomcat) и одном сервере баз данных (mysql). Отдельные серверы не знают друг друга и не могут обмениваться сообщениями. Перед серверами приложений находится один балансировщик нагрузки, который может выполнять липкие сессии.
Таким образом, в основном существует два вида защиты от двойного представления на стороне клиента и на стороне сервера. Если возможно, я хочу перейти на серверную сторону, потому что все методы на стороне клиента, похоже, не работают, если люди отключают куки и / или JavaScript в своих браузерах.
Это заставляет меня задуматься о некоторой синхронизации типа мьютекса с помощью блокировок базы данных. Я думаю, что можно рассчитать контрольную сумму введенных пользователем данных и сохранить их в отдельной таблице базы данных. При каждом представлении заявка должна проверять наличие одинаковой контрольной суммы, которая указывает на то, что данное представление является дубликатом. Конечно, контрольные суммы в этой таблице должны периодически очищаться. Проблема заключается в том, что весь процесс проверки наличия дублирующей контрольной суммы в базе данных и вставки контрольной суммы, если ее нет, является в значительной степени критическим разделом. Поэтому таблицу контрольных сумм необходимо предварительно заблокировать и снова разблокировать после раздела.
Когда я задумываю о замках на столе, начинают звонить мои тупики и сигнальные колокольчики. Поэтому мой вопрос таков: существуют ли более разумные способы предотвращения двойной отправки в веб-приложениях без сохранения состояния?
Обратите внимание, что распорки TokenInterceptor
не может быть применено здесь, потому что это терпит неудачу с треском, когда куки отключены (это зависит от сеанса HTTP, который просто отсутствует без куки сессии).
3 ответа
Более простое решение на основе БД будет примерно таким. Это также можно сделать общим для нескольких форм.
- Иметь таблицу базы данных, которую можно использовать для хранения токенов.
- Когда отобразится новая форма - вставьте новую строку в таблицу токенов и добавьте токен как скрытое поле в форме.
- Когда вы получите форму отправки, выберите вариант для обновления в строке, соответствующей токену, который вы получили как часть формы.
- Если строка все еще существует, то это первая отправка. Обработайте отправку и удалите строку.
- Если строка не существует, то форма уже обработана - вы можете вернуть ошибку.
Классический метод предотвращения двойной отправки - назначить два идентификатора (оба как "скрытое" поле в теге HTML-формы) - один "идентификатор сеанса", который остается неизменным от входа в систему до выхода из системы...
Второй идентификатор меняется с каждой отправкой... на стороне сервера вам нужно только отслеживать "текущий действительный идентификатор" (специфичный для сеанса)... если вы получаете "повторную отправку" (click-happy-user) или "кнопка обновления", или "кнопка возврата", или...) тогда это не будет соответствовать текущему идентификатору... таким образом, вы знаете: это представление должно быть отклонено, а новый идентификатор создан и отправлен обратно с ответом. В некоторых реализациях используется идентификатор, который добавляется в каждую отправку, что немного облегчает часть проверки / отслеживания, но может быть уязвимым для "угадывания" (из соображений безопасности)... Мне нравится генерировать криптографически стойкие идентификаторы для такого рода защиты...
Если у вас есть среда с балансировкой нагрузки с липким сеансом, тогда вам нужно только отслеживать идентификатор на самом сервере (в памяти)... но вы, безусловно, можете сохранить идентификатор в БД... так как вы храните его вместе с идентификатором сеанса блокировка будет на "уровне строки" (не на уровне таблицы), что должно быть в порядке.
То, как вы описали, продвигается на один шаг дальше, изучая контент... НО я вижу часть контента больше на уровне "логики приложения", чем на "уровне предотвращения повторной отправки", так как зависит от логики приложения, хочет ли оно снова принимает те же данные...
Что делать, если вы работаете с липкими сессиями, тогда вам будет хорошо с некоторым TokenManagement. Там существует DoubleClickFilter
который вы можете добавить в свой web.xml
,
Поскольку у вас липкие сессии, вам не нужно Cross-Tomcat-Solution.