2012-06-01 3 views
7

Sto costruendo una semplice app CRUD (non usando il modulo CRUD).Come impedire che i campi nascosti con ID vengano violati

Il mio modello è una classe semplice con un attributo. l'id è implicitamente ereditato dal modello.

@Entity 
public class Account extends Model { 

    @Required 
    public String domain; 
} 

La vista è la seguente. Si prega di notare il campo nascosto 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> 

sono stato in grado di costruire uno scenario in cui salvare, aggiornamento funziona.

Il modo in cui viene eseguito l'aggiornamento è che leggo l'ID dal campo nascosto e aggiorno il record. Se l'ID non è disponibile, viene creato un nuovo record.

Quindi la domanda è: È possibile che l'ID venga violato, modificato in modo da cambiare 1 a 2 e supponendo che un record con 2 esista, viene sovrascritto. (Suppongo che non dovrebbe essere difficile con firebug o altri plugin).

Come si impedisce questo? Un'opzione che ho pensato è quella di leggere il record con l'Id dato, se l'utente è autorizzato a modificarlo, autorizzo l'aggiornamento, altrimenti no. Questo non è ancora infallibile perché, mentre l'utente potrebbe essere autorizzato, il record "errato" potrebbe essere modificato.

Immagino che questo sia un problema noto e, si spera, con una soluzione nota.

Grazie per aver trovato il tempo di rispondere alla mia domanda.

risposta

9

Quindi la domanda è: l'ID può essere violato cioè modificato in modo che cambio 1-2, e assumendo un record con 2 esiste, esso viene sovrascritto. (I supponiamo che non dovrebbe essere difficile con firebug o altri plugin).

Come si impedisce questo? Un'opzione che ho pensato è quella di leggere il record con l'Id dato, se l'utente è autorizzato a modificarlo, consento l'aggiornamento, altrimenti no. Questo non è ancora infallibile perché, mentre l'utente potrebbe essere autorizzato, il record "errato" potrebbe essere modificato.

Ovviamente, è possibile che un utente malintenzionato modifichi l'ID del record.

ci sono diversi modi per minimizzare l'impatto di questo attacco.

1) modo più semplice - oggetto il recupero:

recuperare l'oggetto dal database e verificare se appartiene per l'utente in questione. Ciò impedirà ad altri utenti di fare confusione con oggetti che non appartengono a loro, ma non impedirà a un utente di cambiare un altro oggetto che gli appartiene. Questo è un modo semplice e sufficiente nella maggior parte dei casi.

2) più complicato: firma:

L'idea è quella di segno le costanti forniti al modello e verificare se l'hash corrisponde ancora dopo modulo di presentazione. Questo è molto simile a ciò che il gioco fa con la sua sessione. È impossibile per un utente malintenzionato aggirare le costanti (ad es. Id) e fornisce la massima sicurezza. Tuttavia, avrai più lavoro da fare.

Esempio:

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

nel modello avete

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

nel metodo di lavorazione sotto forma farete

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(); 
    ... 
} 

Speranza che aiuta.

+0

Questo sembra essere esattamente ciò di cui avevo bisogno. Crypto.sign calcola la firma HMAC.SHA1. Lo proverò stasera. Quello con cui stavo rimuginando era avere un segreto specifico dell'utente, ma quello è un dettaglio di implementazione. Hai fornito chiarezza alla foschia nella mia mente. Grazie :) – Nasir

+0

funziona come un fascino. Più semplice del mantenimento dello stato sul server. Ho intenzione di utilizzare le chiavi specifiche dell'utente che genererò al momento dell'iscrizione invece del segreto dell'applicazione che viene utilizzato di default. [Metodo di firma con 2 parametri] (http://www.playframework.org/documentation/api/1.2/play/libs/Crypto.html#sign%28java.lang.String,%20byte []% 29) – Nasir

+0

I ' Non sono sicuro del motivo per cui ti daresti fastidio. Il framework Play è completamente senza stato. Se riesce a capire che solo l'ID account 1 può essere modificato sul GET, perché non lo può capire di nuovo sul POST? La sessione identifica già l'utente. Non c'è motivo di crittografare qualcos'altro. –

1

Sì, può essere modificato. Non ci vuole alcuna conoscenza o abilità per farlo. In ogni caso, le informazioni che provengono dall'utente non devono essere attendibili fino a quando non hai verificato diversamente.

Per fare ciò, è necessaria una sorta di logica lato server. In molti casi, questa è solo una sessione collegata al server all'oggetto utente, che consente di eseguire l'autorizzazione (ci si assicura che il record sia uno che possono modificare, quale conta meno ed è un errore intenzionalmente causato dall'utente, non un rischio per la sicurezza).

Fintanto che è possibile legare la richiesta a un utente, quindi assicurarsi che l'utente è autorizzato a eseguire la richiesta, sei a posto. Il modo più semplice per farlo è tipicamente sessioni, ma c'è molto spazio.

2

È possibile che l'ID venga violato, modificato in modo da modificare da 1 a 2 e supponendo che un record con 2 esista, venga sovrascritto. (Suppongo che sia non dovrebbe essere difficile con firebug o altri plugin).

Sei corretto. La modifica di tali elementi può essere semplice come controllare e modificare l'elemento nella console di Chrome. Ricorda; tutto ciò che viene fatto lato client non è sicuro e può essere modificato dall'utente. Avere sempre i controlli sul lato server, sempre.

Come si impedisce?

Una possibile soluzione è collegare i record agli utenti, ad es., crea una tabella di bridging tra utenti e record chiamata "recordAccess" (o qualunque sia la convenzione di denominazione che ti porta a chiamarla). Questa tabella di bridging avrà una colonna ID utente e una colonna ID record. Il server controllerà l'ID utente e l'ID del record rispetto a questa tabella e consentirà le modifiche solo se nel database è presente una riga corrispondente. Il modo in cui aggiungi righe a questa tabella dipende da come funziona la tua app, ma non dovrebbe essere difficile da risolvere.

Per impedire agli utenti di modificare il record sbagliato, è possibile aggiungere una colonna aggiuntiva in questa tabella di bridging denominata "corrente" (o, ancora, qualsiasi cosa si preferisca) che è un semplice valore booleano. Quando l'utente va a modificare un record che è autorizzato a modificare, questo valore verrà impostato su "true" e tutte le altre righe associate a quell'utente saranno impostate su "false". Quindi, quando l'utente invia la modifica, se il valore in quella riga è impostato su "true", la riga viene aggiornata correttamente e il valore torna a "falso". In caso contrario, tutti i valori sono impostati su "false" e l'aggiornamento viene rifiutato.

Speriamo che questo ti dia qualche idea.

+0

Grazie. In questo momento, sto esplorando una combinazione di questo con una sorta di digest di messaggi. HMAC (rfc 2104) sembra adattarsi al conto. Devo capirlo meglio. Aggiornerà questo thread se faccio qualche progresso. – Nasir