PHP: предотвращение случайной повторной обработки формы при нажатии кнопки Back - PullRequest
4 голосов
/ 30 октября 2009

Каков наилучший способ предотвратить повторную обработку формы, когда пользователь нажимает кнопку Назад?

Я следую шаблону Post / Redirect / Get , поэтому у меня нет проблем, если нажать F5, но кнопка «Назад» все еще дает возможность повторно отправить форму. Если эта форма является страницей обработки кредитной карты, это плохо.

Этот вопрос был задан несколько здесь , но формулировки и ответы были низкого качества и не были конкретно связаны с этой проблемой.

У меня есть form.php, который подчиняется себе. Если при отправке не было ошибок во входных данных, пользователь перенаправляется на form_thanks.php. Нажатие (и «Отправить» или «Повторная передача») после повторной отправки form.php (ПЛОХО!) И затем возвращает их обратно в form_thanks.php.

Пожалуйста, включите также решения, которые не включают использование сессий, если это возможно.

Ответы [ 6 ]

7 голосов
/ 30 октября 2009

Я бы сделал это по-другому. Поместите скрытый ввод со случайной строкой в ​​качестве значения, и когда он будет представлен, сохраните эту случайную строку в сеансе. Настройте простую проверку, чтобы увидеть, опубликовали ли они это, и не принимают ли они ввод.

2 голосов
/ 02 ноября 2009

Это должно быть сделано с помощью одноразового токена или nonce . Php / server должен включить этот токен в скрытое поле формы.

Он должен хранить список всех последних токенов, и каждый раз, когда форма отправляется, он должен проверять, есть ли токен в списке последних действительных токенов.

Если его нет в списке, не перерабатывайте форму.
Если он есть в списке, обработайте форму и удалите токен из списка.

Токены могут обрабатываться в течение сеансов или просто в виде таблицы базы данных без сеансов. Хотя токены должны быть привязаны к пользователю.

Это также рекомендуемый способ избежать CSRF атак.

1 голос
/ 17 ноября 2009

Поздний ответ, но можно полностью избежать обработки, используя решение на основе AJAX; не было бы проблемы с включением одноразового номера в эту схему обработки, но при использовании асинхронного запроса, который, в случае успеха, перенаправляет пользователя, запросы не повторяются при обновлении, нажатии назад или чем-либо, кроме нажатия кнопки.

Также легко реализовать механизм, который предотвращает либо двойное нажатие кнопки, либо ее «блокировку», если что-то произошло во время запроса, путем встраивания в обработчик запроса (будь то высокий уровень с PrototypeJS или jQuery или низкий уровень с вашей управляемой функцией) механизмы включения и выключения кнопки, когда запрос завершается и запускается соответственно.

1 голос
/ 30 октября 2009

Просто мысли вслух. Но как насчет варианта post / redirect / get, где окончательное получение на самом деле не является окончательным получением;) Скорее, оно, в свою очередь, всегда автоматически переходит на действительно окончательную страницу, поэтому, если пользователь нажимает кнопку возврата, он возвращает прямо откуда они пришли?

EDIT:

Хорошо, принимая во внимание комментарий ОП, вот еще одна идея. URL для отправки формы может быть сделан так, чтобы требовать параметр, который подходит только для одного использования. Этот токен будет сгенерирован (с использованием MD5 или чего-то подобного) перед отправкой формы и может быть сохранен в базе данных (в ответ на чье-то предложение вы запросили решение без использования сессий). После обработки формы этот токен будет помечен в базе данных как уже использованный. Чтобы при возврате страницы с тем же маркером можно было предпринять шаги для предотвращения повторной отправки данных формы на сервер.

0 голосов
/ 02 октября 2012

Попробуйте это:

<SCRIPT type="text/javascript">
    window.history.forward();
</SCRIPT>
0 голосов
/ 30 октября 2009

Я обнаружил, что back вернет форму в состояние, в котором она находилась до перенаправления страницы, если это так, имеет скрытый ввод / переменную или что-то, начинающееся со значения, скажем true, затем после отправки формы, и если значение равно true, измените его на false и затем отправьте, иначе верните false

...