2012-06-01 13 views
7

Estoy construyendo una aplicación CRUD sencillo (no usar el módulo CRUD).Cómo prevenir los campos ocultos con el ID de ser atacado

Mi modelo es una clase simple con un solo atributo. el id se hereda de manera implícita de Model.

@Entity 
public class Account extends Model { 

    @Required 
    public String domain; 
} 

La vista es la siguiente. Tenga en cuenta el campo oculto con id.

<form class="form-horizontal" action="@{Application.save}" method="POST"> 
<fieldset> 
    <legend>Settings</legend> 
    <input type="hidden" name="account.id" value="${account?.id}"> 

    #{field 'account.domain'} 
    <div class="control-group #{if field.error != null} error #{/if}"> 
     <label class="control-label" for="${field.id}">&{field.name}</label> 
     <div class="controls"> 
      <input type="text" class="input-xlarge" id="${field.id}" value="${field.value}" name="${field.name}"> 
      <span class="help-inline">${field.error}</span> 
     </div>   
    </div> 
    #{/field}   

    <div class="form-actions"> 
     <input class="btn btn-primary" type="submit" value="Save"> 
    </div> 

</fieldset> 

que han sido capaces de construir un escenario en el que guardar, actualizar funciona.

La forma en que se realiza la actualización es que leo el ID del campo oculto y actualizo el registro. Si ID no está disponible, se crea un nuevo registro.

Así que la pregunta es: Se puede hackear la ID, es decir, modificarla para que cambie 1 a 2, y suponiendo que exista un registro con 2, se sobrescribe. (Supongo que no debería ser difícil con Firebug u otros complementos).

¿cómo puedo evitar esto? Una opción que pensé es leer el registro con el Id dado, si el usuario puede modificarlo, permito la actualización, de lo contrario no. Esto todavía no es infalible porque, aunque se podría permitir al usuario, el registro "incorrecto" podría modificarse.

Imagino que este es un problema conocido y con suerte con una solución conocida.

Gracias por tomarse el tiempo para responder a mi pregunta.

Respuesta

9

Así que la pregunta es: ¿Puede el ID de ser pirateado es decir modificado de modo que puedo cambiar 1 a 2, y asumiendo un registro con 2 existe, se sobreescribe. (I supongo que no debería ser difícil con Firebug u otros complementos).

¿Cómo puedo evitar esto? Una opción que pensé es leer el registro con el Id dado, si el usuario puede modificarlo, permito actualizar, de lo contrario no. Esto todavía no es infalible porque, aunque se podría permitir el usuario , el registro "incorrecto" podría modificarse.

Por supuesto, es posible que un atacante cambie la identificación del registro.

Existen varias formas de minimizar el impacto de este ataque.

1) más fácil manera - de objetos ir a buscar:

buscar el objeto en la base de datos y comprobar si pertenece al usuario en cuestión. Esto evitará que otros usuarios jueguen con objetos que no les pertenecen, pero no impedirá que un usuario cambie otro objeto que le pertenece. Esta es una manera fácil y suficiente en la mayoría de los casos.

2) más complicado: firma:

La idea aquí es señal de las constantes suministrados por el usuario a la plantilla y comprobar si coincide con el hash aún después de envío del formulario. Esto es muy similar a lo que hace el juego con su sesión. Es imposible para un atacante meterse con las constantes (por ejemplo, id) y proporciona la mayor seguridad ... sin embargo, tendrá más trabajo por hacer.

Ejemplo:

public static void someActionDisplayingForm(){ 
    SomeObject o = .... 
    SomeOtherObject o2 = .... 
     String constants = o.id + "|" + o2.id; 
     String hash = Crypto.sign(constants); 
     render(o, o2, hash); 
} 

en la plantilla que tiene

#{form ...} 
    <input type='hidden' name='id1' value='${o.id}' /> 
    <input type='hidden' name='id2' value='${o2.id}' /> 
    <input type='hidden' name='hash' value='${hash}' /> 

en el método de procesamiento de la forma que va a hacer

public static void processing(String id1, String id2, String hash, String otherValues, ...){ 
    String constants = id1 + "|" + id2; 
    String checkHash = Crypto.sign(constants); 
    if(!checkHash.equals(hash)) 
    badRequest(); 
    ... 
} 

Espero que ayude.

+0

Esto parece ser exactamente lo que necesitaba. Crypto.sign calcula la firma HMAC.SHA1. Voy a probarlo esta noche. Lo que había estado reflexionando era tener un secreto específico del usuario, pero ese es un detalle de implementación. Has proporcionado claridad a la neblina en mi mente. Gracias :) – Nasir

+0

funciona como un encanto. Más simple que mantener el estado en el servidor. Planeo usar claves específicas del usuario que generaré en el momento de la suscripción en lugar del secreto de la aplicación que se usa de forma predeterminada. [Método de firma con 2 params] (http://www.playframework.org/documentation/api/1.2/play/libs/Crypto.html#sign%28java.lang.String,%20byte []% 29) – Nasir

+0

I ' No estoy seguro de por qué te molestaría. Play Framework es completamente sin estado. Si se da cuenta de que solo se puede modificar el ID de cuenta 1 en el GET, ¿por qué no puede resolverlo de nuevo en el POST? La sesión ya identifica al usuario. No hay ninguna razón para encriptar nada más. –

1

Sí, puede ser modificado. No requiere conocimiento o habilidad real para hacerlo. En cualquier caso, la información que proviene del usuario no debe ser confiable hasta que haya verificado lo contrario.

Para hacer eso, necesita algún tipo de lógica del lado del servidor. En muchos casos, eso es sólo una sesión vinculada en el servidor al objeto de usuario, lo que permite llevar a cabo la autorización (a asegurarse de que el registro es uno que puede modificar; cuál es menos importante y es un error intencional usuario causado, no una riesgo de seguridad).

Mientras pueda volver a vincular la solicitud a un usuario, asegúrese de que el usuario puede ejecutar la solicitud, está bien. La forma más fácil de hacerlo es típicamente sesiones, pero hay mucho espacio.

2

Se puede hackear la ID, es decir, modificar para que cambie 1 a 2, y suponiendo que exista un registro con 2, se sobrescribe. (Supongo que no debería ser difícil con Firebug u otros complementos).

Usted está correcto. Editar estas cosas puede ser tan fácil como inspeccionar y editar el elemento en la consola de Chrome. Recuerda; cualquier cosa que se haga desde el lado del cliente es insegura y puede ser modificada por el usuario. Siempre tenga comprobaciones del lado del servidor, siempre.

¿Cómo puedo evitar esto?

Una posible solución es vincular los registros a los usuarios, es decir, cree una tabla puente entre usuarios y registros llamada "recordAccess" (o lo que su convención de nomenclatura lo lleve a llamar). Esta tabla de puente tendrá una columna de ID de usuario y una columna de ID de registro. El servidor verificará la identificación del usuario y la identificación del registro en esta tabla y solo permitirá cambios si hay una fila coincidente en la base de datos. La forma de agregar filas a esta tabla depende de cómo funciona su aplicación, pero no debería ser difícil de resolver.

Para evitar que los usuarios editen el registro incorrecto, puede agregar una columna adicional en esta tabla de puente llamada "actual" (o, nuevamente, lo que prefiera) que es un valor booleano simple. Cuando el usuario va a editar un registro que puede editar, este valor se establecerá en "verdadero" y todas las demás filas asociadas con ese usuario se establecerán en "falso". Luego, cuando el usuario envía la edición, si el valor en esa fila se establece en "verdadero", la fila se actualiza con éxito y el valor vuelve a ser "falso". De lo contrario, todos los valores se establecen en "falso" y la actualización se rechaza.

Espero que esto te dé algunas ideas.

+0

Gracias. En este momento, estoy explorando una combinación de esto con algún tipo de resumen de mensaje. HMAC (rfc 2104) parece ajustarse a la factura. Necesito entenderlo mejor. Actualizaré este hilo si hago algún progreso. – Nasir

Cuestiones relacionadas