2010-05-21 17 views
5

Tengo un POJO en Google Web Toolkit como este que puedo recuperar del servidor.Seguridad al usar GWT RPC

class Person implements Serializable { 
    String name; 
    Date creationDate; 
} 

Cuando el cliente realiza cambios, volver a guardarlo en el servidor mediante el GWT RemoteServiceServlet así:

rpcService.saveObject(myPerson,...) 

El problema es que el usuario no debe ser capaz de cambiar la creationDate. Como el método RPC es realmente solo un HTTP POST para el servidor, sería posible modificar el creationDate cambiando la solicitud POST.

Una solución simple sería crear una serie de funciones RPC como changeName(String newName), etc., pero una clase con muchos campos requeriría muchos métodos para cada campo y sería ineficaz al cambiar muchos campos a la vez.

Me gusta la simplicidad de tener un único POJO que pueda usar tanto en el servidor como en el cliente GWT, pero necesito una forma de hacerlo de forma segura. ¿Algunas ideas?

EDITAR

que estoy de volver a presentar con una recompensa para tratar de ver si hay alguna otra idea. Tal vez mi pregunta original se centró demasiado en los detalles de GWT. Realmente creo que esta es una pregunta genérica para cualquier sistema que use JavaBeans para pasar datos entre un entorno seguro (contenedor de servlets) y un entorno inseguro (navegador web).

EDIT 2

También, para ser claros, I utilizado el campo creationDate como un ejemplo del problema. En realidad, el código con el que estoy trabajando es más complicado con muchos campos diferentes.

+0

Acerca de EDIT 2: No creo, hay mucha diferencia entre el campo creationDate y otros campos, excepto que creationDate puede tener algunas complejidades adicionales que son típicas para la gestión de fecha/hora. Los permisos son la forma habitual de manejar todos los datos que entran y salen; para algunos objetos/campos, esto es muy fácil al negar siempre todas las actualizaciones. Para otros objetos/campos, los permisos pueden ser muy elaborados, basados ​​en comprobaciones en estructuras de datos complejas, evaluadas individualmente para cada usuario. En cualquier caso, los controles se realizan en el servidor; no los haga en el cliente. –

Respuesta

3

Te recomiendo que mantengas tu único método RPC, y utilices un mapeador POJO/bean como Dozer o Gilead.

  • Con dormilón, se crea un class-mapping que se utiliza para copiar las propiedades de un objeto a otro. Si no especifica una propiedad en el mapeo de clase, no se copiará.
  • Con Gilead, el @ReadOnly transport annotation debería ser suficiente.

El beneficio colateral es que usted no necesita cambiar su capa de acceso de datos (suponiendo que tiene uno). No importa si usa un ORM o no, con una base de datos relacional o no.

0

Bueno ... una solución académica (es decir, teóricamente posible, pero bastante impráctica) podría ser ajustar el estado del objeto utilizando una clave pública descartada cuya clave privada está en el servidor. Podría ser algo como esto:

  1. el servidor genera un par de claves pública-privada
  2. el servidor envía la clave pública junto con los datos reales para el cliente
  3. el cliente calcula un hash del objeto de plena estado junto con la clave pública
  4. el cliente envía el objeto y el hash al servidor
  5. el servidor vuelve a calcular el hash para confirmar la integridad del paquete

Suponiendo que el par de claves se cambia en cada requset y que el usuario no puede interferir con el proceso de hashing (que puede, pero puede ser lo suficientemente difícil como para hacerlo útil en algunos casos de uso), el servidor podría detectar cualquier cambio en el estado de los objetos hecho después de que se haya calculado el hash en el cliente.

De nuevo, consideren esto como algo más que un experimento mental ... No recomendaría que implementen tal enfoque. En general, debe poder garantizar que la lógica en el cliente no haya sido manipulada antes de llegar a proteger los datos.

+1

¿Por qué alguien agregaría la complejidad de la criptografía solo para evitar las actualizaciones de la base de datos en columnas predeterminadas? – jweyrich

+0

Como dije, no es algo que recomendaría hacer. Comprendí que la pregunta era básicamente "cómo evitar que el usuario cambie una parte de un valor (en el entorno tecnológico dado)". Una solución obvia para mí es firmar los datos para garantizar que no hayan sido manipulados. Quizás entendimos la pregunta de diferentes maneras. –

+0

Usted entiende el problema como "Cómo evitar la manipulación del tráfico". Si fuera el caso, simplemente podría usar HTTPS. – jweyrich

3

Si el cliente no puede cambiar el creationDate y hacer que se adhiera, cambie su serialización (p.su instrucción SQL UPDATE) para no guardar ese campo específico. Solo se debe configurar desde INSERT (donde vendrá desde el servidor de punto final RPC o su servidor de base de datos si establece un valor predeterminado automático).

+2

Exactamente. "Nunca confíes en el cliente". Si tiene información que el usuario no debería poder cambiar, no confíe en los datos que provienen del cliente. Si no está guardando los datos en un almacenamiento persistente hasta que el usuario tenga la oportunidad de modificarlos, serialícelos de antemano y guarde una copia temporal para extraer los datos que no se supone que se han modificado. –

1

que haría uso de un enfoque basado en los permisos:

  • asignar funciones a los usuarios (por ejemplo, usuario administrador, usuario conectado, el usuario invitado, ...), y
  • asociado con esas funciones permisos (por ejemplo, puede leer el nombre de la persona, puede modificar el nombre de la persona, quizás limitando aún más a ciertas personas, etc.)

En cada solicitud del cliente, realice una comprobación en el servidor, si el usuario puede realizar esa acción En el caso de las "fechas de creación", esto probablemente nunca esté permitido para nadie. Así

  • si la solicitud contiene una fecha de creación, puede mostrar un mensaje de error o ignorar la petición ...
  • si la solicitud no contiene una fecha de creación (caso habitual), se crea la fecha en el servidor - o si la persona ya tiene una fecha de creación, reutilícela.

El cliente generalmente especificará a la persona mediante algún tipo de ID (puede ser nulo para una persona recién creada), que el servidor puede usar para buscar personas existentes. La alteración del ID no debería importar, ya que el usuario solo puede modificar los datos especificados por sus permisos de todos modos.

Caso especial:

Si realmente tiene que utilizar una fecha de creación suministra el cliente, porque quiere saber un poco más exactamente cuando el usuario ha hecho clic, lo único que puede hacer es para verificar que la fecha de creación suministrada se encuentre entre la solicitud anterior y la solicitud actual. Sin embargo, debe tener en cuenta la diferencia horaria entre el servidor y el cliente. Y no puedes garantizar la precisión.

+0

Esta respuesta se refiere principalmente a la parte genérica al final de su pregunta. Con GWTRPC, si desea enviar todo el objeto Person, puede permitir que contenga una fecha de creación, pero a) lo ignora, o b) verifica que coincida con el del objeto en el servidor. –

1

¿Por qué no hacer que los campos sean privados y solo proporcionan un getCreationDate() y ningún setCreationDate()?

1

Simplemente puede ignorar los valores para los campos inmutables.
Si eso no es posible debido a la configuración de su mecanismo de persistencia en el servidor, cuando la solicitud llegue al servidor, recupere otra instancia del POJO del almacén persistente y llene los campos que son inmutables con los que acaba de crear tiene.De esa manera alguien manipuló algunos de los campos que no te importan.

Por supuesto, el cifrado también puede ser una solución para ayudar a evitar la manipulación.

1

Divida sus objetos en dos partes. Uno contiene solo los campos que el cliente puede editar. Envíe ambos objetos al cliente, pero solo guarde el objeto editable cuando el cliente lo devuelva. Puedes usar herencia aquí para hacer tu vida más simple.

Si su herramienta de mapeo no se dobla como usted desea, implemente un método copy() que copie todos los campos de un objeto a otro. Luego puede cargar una nueva instancia del objeto desde su base de datos, copiar los campos editables en él y luego guardar el objeto modificado.

Cuestiones relacionadas