2008-11-20 14 views
5

Estoy armando una pequeña aplicación web que escribe en una base de datos (Perl CGI & MySQL). El script CGI toma información de un formulario y lo escribe en una base de datos. Noté, sin embargo, que si presiono 'Volver a cargar' o 'Atrás' en el navegador web, volverá a escribir los datos en la base de datos. No quiero esto¿Cómo puedo evitar que se vuelva a escribir la base de datos cuando el navegador realiza una recarga/devolución?

¿Cuál es la mejor manera de protegerse contra los datos que se vuelven a escribir en este caso?

Respuesta

17

¡No utilice las solicitudes GET para realizar modificaciones! Be RESTful; use POST (o PUT) en su lugar, el navegador debe advertir al usuario que no vuelva a cargar la solicitud. Redirigir (using HTTP redirection) a una página de recibo utilizando una solicitud GET normal después de una solicitud POST/PUT permitirá refrescar la página sin que se le advierta acerca de volver a enviarla.

EDIT:

que asumir el usuario está conectado de alguna manera, y por lo tanto ya fuiste tener alguna manera de rastrear al usuario, por ejemplo, sesión o similar.

Se podría hacer una marca de tiempo (o un hash aleatoria etc ..) cuando se muestra la forma de almacenarlo tanto como un campo oculto (justo al lado de la lucha contra Solicitud Cross-Site símbolo Estoy seguro de que tiene allí noté) y en una variable de sesión (que se almacena de forma segura en su servidor), cuando recibe una solicitud POST/PUT para este formulario, comprueba que la marca de tiempo sea la misma que la sesión. Si es así, estableces la marca de tiempo en la sesión en algo variable y difícil de adivinar (la marca de tiempo concatenada con alguna cadena secreta, por ejemplo) y luego puedes guardar los datos del formulario. Si alguien repite la solicitud ahora, no encontrará el mismo valor en la variable de sesión y rechazará la solicitud.

El problema al hacer esto es que el formulario no es válido si el usuario hace clic atrás para cambiar algo, y puede ser un poco duro, a menos que sea dinero lo que está actualizando. Por lo tanto, si tiene problemas con usuarios "estúpidos" que actualizan y hacen clic en el botón "Atrás" accidentalmente reenviando algo, simplemente usar POST les recuerda que no hagan eso, y redirigir lo hará menos probable. Si tiene un problema con usuarios malintencionados, también debe usar un intervalo de tiempo, aunque a veces puede confundir a los usuarios, aunque si los usuarios publican deliberadamente el mismo mensaje una y otra vez, es probable que deba encontrar una forma de prohibirlos. Usar POST, tener un timestam e incluso hacer una comparación completa de toda la base de datos para buscar publicaciones duplicadas, no servirá de nada si los usuarios maliciosos simplemente escriben un script para cargar el formulario y enviar basura al azar automáticamente. (Pero la protección de solicitud entre sitios lo hace mucho más difícil)

+0

El OP se queja de que sus usuarios han estropeado el sistema. Decir "hacer que su navegador intente detenerlos" no es una solución sólida para el problema. –

+2

No, pero hace que los usuarios benignos sean menos propensos a hacerlo, agregué algunas ideas para reducir aún más el problema. –

4

Me resulta útil para rastrear el número de presentaciones de formularios que el usuario ha realizado en su sesión. Luego, al renderizar el formulario, creo un campo oculto que contiene ese número. Si el usuario vuelve a enviar el formulario presionando el botón Atrás, enviará el viejo # y el servidor puede decir que el usuario ya ha enviado el formulario al examinar lo que está en la sesión a lo que está diciendo el formulario.

Sólo mis 2 centavos.

6

El uso de una solicitud POST hará que el navegador intente evitar que el usuario vuelva a enviar la misma solicitud, pero yo recomendaría el uso de seguimiento de transacciones basado en sesiones de algún tipo para que el usuario ignore las advertencias del navegador y vuelve a enviar su consulta, su aplicación evitará la duplicación de cambios en la base de datos. Puede incluir una entrada oculta en el formulario de envío con el valor establecido en un hash de cifrado y registrar ese hash si la solicitud se envía y procesa sin error.

1

Si aún no está utilizando algún tipo de gestión de sesión (que le permitiría observar y rastrear envíos de formularios), una solución simple sería incluir algún tipo de identificador único en el formulario (como un elemento oculto) eso es parte de la transacción DB principal en sí o rastreado en una tabla DB separada. Luego, cuando se envía un formulario, verifica la identificación única para ver si ya se ha procesado. Y cada vez que se genera el formulario, solo tiene que asegurarse de tener una ID única.

+0

Usted emite un número de ticket, luego solo perfora el ticket una vez. – dkretz

1

En primer lugar, no puede confiar en el navegador, por lo que cualquier conversación sobre el uso de POST en lugar de GET es principalmente nerd flim-flam. Sí, el cliente podría recibir una advertencia del tipo "¿Quería volver a enviar esta información nuevamente?", Pero es muy probable que diga "Sí, ahora déjeme en paz, estúpida computadora".

Y con razón: si no quiere envíos duplicados, entonces es su problema resolver, no del usuario.

Es probable que tenga una idea de lo que significa ser un envío duplicado. Tal vez sea la misma dirección IP en unos segundos, tal vez sea el mismo título de una publicación de blog o una URL que se haya enviado recientemente. Tal vez es una combinación de valores, p. La dirección IP, la dirección de correo electrónico y el asunto del envío de un formulario de contacto. De cualquier forma, si ha detectado manualmente algunos duplicados en sus datos, debería poder encontrar una forma de identificar mediante programación un duplicado en el momento de la presentación, y marcarlo para su aprobación manual (si no está seguro), o simplemente le dice al remitente "¿Ha hecho doble clic?" (Si la información no es increíblemente confidencial, puede presentar el registro existente que tiene para ellos y decir "¿Es esto lo que usted quiso enviarnos? Si es así, ya lo ha hecho - ¡hurra!")

1

I No confiaría en las advertencias POST del navegador. Los usuarios simplemente hacen clic en Aceptar para que los mensajes desaparezcan.

Cada vez que tenga una solicitud que debe ser una sola vez, por ejemplo, 'realice un pago', envíe un token único hacia abajo, que se envía de nuevo con la solicitud. Tira el token después de que vuelva, y entonces ahora puedes decir cuándo algo es un envío válido (cualquier cosa con un token que no esté 'activo'). Vencer los tokens activos después de X cantidad de tiempo, p. cuando finaliza una sesión de usuario

(seguimiento de forma alterna las fichas que han regresado, y si ha recibido antes de esa fecha no es válido.)

+0

Todavía hay un problema con las condiciones de carrera. Tan pronto como reciba el token, debe verificar que no se haya usado previamente, p. emite un comando de actualización de SQL y verifica si el valor de retorno es 1 (cambiaste algo) o 0E0 (intentaste cambiarlo a lo que ya era). –

0

hacer un post cada vez que se alteren los datos, pero nunca devolverá una respuesta de HTML a partir de un poste. .. en su lugar devuelve un redireccionamiento a un GET que recupera los datos actualizados como una página de confirmación. De esta forma, no hay que preocuparse de que actualicen la página. Si se actualizan, todo lo que sucederá es otra recuperación, nunca una acción que altere los datos.

Cuestiones relacionadas