Как я могу предотвратить повторную запись базы данных, когда браузер перезагружается / возвращается? - PullRequest
5 голосов
/ 20 ноября 2008

Я собираю небольшое веб-приложение, которое пишет в базу данных (Perl CGI & MySQL). CGI-скрипт берет некоторую информацию из формы и записывает ее в базу данных. Однако я заметил, что если я нажму «Перезагрузить» или «Назад» в веб-браузере, он снова запишет данные в базу данных. Я не хочу этого

Каков наилучший способ защиты от перезаписи данных в этом случае?

Ответы [ 7 ]

17 голосов
/ 20 ноября 2008

Не используйте GET-запросы для внесения изменений! Be RESTful ; используйте POST (или PUT), вместо этого браузер должен предупредить пользователя не перезагружать запрос. Перенаправление ( с использованием перенаправления HTTP ) на страницу квитанции с использованием обычного запроса GET после запроса POST / PUT позволит обновить страницу без предупреждения о повторной отправке.

EDIT:

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

Вы можете сделать временную метку (или случайный хеш и т. Д.) При отображении формы, хранящей ее как скрытое поле ( только помимо токена анти-межсайтового запроса, я уверен, что у вас уже есть там ) и в переменной сеанса (которая безопасно хранится на вашем сервере), когда вы получаете запрос POST / PUT для этой формы, вы проверяете, что метка времени совпадает с меткой в ​​сеансе. Если это так, вы устанавливаете временную метку в сеансе на переменную, которую сложно угадать (например, временную метку, соединенную с какой-то секретной строкой), затем вы можете сохранить данные формы. Если кто-то повторяет запрос сейчас, вы не найдете то же значение в переменной сеанса и отклоните запрос.

Проблема с этим заключается в том, что форма недействительна, если пользователь щелкает обратно, чтобы что-то изменить, и это может быть немного грубым, если только вы не обновляете деньги. Поэтому, если у вас есть проблемы с «глупыми» пользователями, которые обновляют и нажимают кнопку «Назад», таким образом, случайно перепостывая что-то, простое использование POST напомнит им не делать этого, а перенаправление сделает это менее вероятным. Если у вас есть проблема со злонамеренными пользователями, вы должны также использовать временную отметку, хотя это иногда будет сбивать с толку пользователей, хотя, если пользователи намеренно публикуют одно и то же сообщение снова и снова, вам, вероятно, необходимо найти способ их запретить. Использование POST, наличия временной отметки и даже полного сравнения всей базы данных для проверки на наличие дублирующих сообщений вообще не поможет, если злонамеренные пользователи просто напишут скрипт для автоматической загрузки формы и отправки случайного мусора. (Но защита от межсайтовых запросов делает это намного сложнее)

6 голосов
/ 20 ноября 2008

Использование запроса POST приведет к тому, что браузер попытается предотвратить повторную отправку того же запроса пользователем, но я бы рекомендовал использовать какое-либо отслеживание транзакций на основе сеанса, чтобы пользователь игнорировал предупреждения от браузера и повторно отправит свой запрос, ваше приложение предотвратит дублирование изменений в базе данных. Вы можете включить скрытый ввод в форму отправки со значением, установленным в криптографический хеш, и записать этот хэш, если запрос отправлен и обработан без ошибок.

4 голосов
/ 20 ноября 2008

Мне удобно отслеживать количество отправленных форм, которые пользователь выполнил в своем сеансе. Затем при рендеринге формы я создаю скрытое поле, которое содержит это число. Если пользователь затем повторно отправляет форму, нажав кнопку «Назад», он отправит старый #, и сервер может сказать, что пользователь уже отправил форму, изучив то, что находится в сеансе, и что говорит форма.

Только мои 2 цента.

1 голос
/ 22 ноября 2008

Я бы не стал полагаться на предупреждения POST от браузера. Пользователи просто нажимают OK, чтобы сообщения исчезли.

Каждый раз, когда у вас будет запрос, который должен быть выполнен только один раз, например, «сделать платеж», отправьте уникальный токен, который будет отправлен обратно вместе с запросом. Выкиньте токен после того, как он вернется, и теперь вы можете сказать, когда что-то является действительной отправкой (что-нибудь с токеном, который не является «активным»). Срок действия активных токенов истекает через X раз, например когда пользовательский сеанс заканчивается.

(поочередно отслеживайте возвращенные токены, и если вы получили их ранее, то они недействительны.)

1 голос
/ 22 ноября 2008

Прежде всего, вы не можете доверять браузеру, поэтому любые разговоры об использовании POST, а не GET - это в основном болван. Да, клиент может получить предупреждение в виде «Вы хотели снова отправить эти данные?», Но они вполне могут сказать «Да, теперь оставьте меня в покое, тупой компьютер».

И правильно: если вы не хотите дублировать материалы, решать вам, а не пользователю.

Вы, вероятно, имеете некоторое представление о том, что значит быть дублированным представлением. Может быть, это тот же IP в течение нескольких секунд, может быть, это тот же заголовок сообщения в блоге или URL, который был представлен недавно. Может быть, это комбинация значений - например, IP-адрес, адрес электронной почты и тематический заголовок представления контактной формы. В любом случае, если вы вручную обнаружили некоторые дубликаты в своих данных, вы сможете найти способ программно идентифицировать дубликат во время представления и пометить его для подтверждения вручную (если вы не уверены), или просто сказать подателю "Вы дважды щелкнули?" (Если информация не является на удивление конфиденциальной, вы можете представить имеющуюся у вас запись и сказать: «Это то, что вы намеревались отправить нам? Если да, то вы уже сделали это - ура»)

1 голос
/ 21 ноября 2008

Если вы еще не используете какое-либо управление сеансами (которое позволит вам отмечать и отслеживать отправку форм), простое решение будет включать в форму какой-то уникальный идентификатор (как скрытый элемент), который является либо частью самой основной транзакции БД, либо отслеживается в отдельной таблице БД. Затем, когда вам отправляют форму, вы проверяете уникальный идентификатор, чтобы увидеть, был ли он уже обработан. И каждый раз, когда формируется сама форма, вам просто нужно убедиться, что у вас есть уникальный идентификатор.

0 голосов
/ 12 августа 2010

Делайте POST каждый раз, когда вы изменяете данные, но никогда не возвращаете HTML-ответ от сообщения ... вместо этого возвращайте перенаправление на GET, который получает обновленные данные в качестве страницы подтверждения. Таким образом, не стоит беспокоиться о том, что они обновляют страницу. Если они обновляются, все, что произойдет, - это другое извлечение, а не изменение данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...