Tecniche migliori rispetto alla crittografia dei parametri url

17

Sono un programmatore che lavora su un'applicazione in cui l'unica scelta / vs / scadenza era implementare la crittografia simmetrica sui valori dei parametri dell'URL. I dati sono di natura insensibile, ma dovevamo impedire agli agenti di vendita di sbirciare a vicenda. (Le chiavi vengono generate durante la creazione della sessione e sono crittograficamente forti.) Le sessioni dovrebbero terminare frequentemente.

La gerarchia dei ruoli era Manager - > Supervisor - > Agents. Le strutture dati attualmente non spiegano questi ruoli in modo da imporre rigorosamente chi può vedere cosa. Ottenere queste informazioni dal database NON era da nessuna parte vicino alla semplice. (Database ricorsivo.)

So che questa tecnica è in fondo alla lista come difesa dalla manipolazione dei parametri. Quale sarebbe stata una tecnica migliore?

Vincoli:
Il controllo basato sui ruoli non è un'opzione.

[Informazioni aggiuntive] Gli URL creati e inviati al client prima di apportare eventuali modifiche assomigliavano a:

https://www.example.com/agent/?producerId=12345

La superficie della minaccia specifica qui è la manipolazione dei parametri contro? agentId = 12345. Gli ID agente sono assegnati in modo univoco a ciascun agente. Quindi, se l'Agente A vuole esaminare le statistiche dell'Agente B, potrebbe aver inserito agentId = 22222 per esaminare le quotazioni dell'agente e le statistiche di vendita correnti.

Anche in questo caso, il controllo basato sul ruolo non era un'opzione per me: non ero in grado di apportare modifiche al database O al livello di persistenza.

La mia soluzione era usare una chiave di crittografia creata dalla sessione (usando la classe KeyGenerator di Java) e crittografare gli url in uscita inviati al client. Quindi ora l'url ha il seguente aspetto:

https://www.example.com/agent/?producerId=<ciphertext>

Ora, se qualcuno prova agentId = 22222, il server decodifica ciò che pensa è testo cifrato e alla fine creerà una sequenza di caratteri non valida.

(Ciò lascia aperta la possibilità che venga trovato un agentId esistente , ma abbastanza improbabile che sia pertinente per la persona che esegue l'attacco.

Sottolineerò che questa domanda non riguarda la sicurezza ottimale (che sarebbe un controllo basato sui ruoli per garantire l'accesso alle risorse) e sul tentativo di spremere un po 'di sicurezza in un'area grigia.
=============== Aggiornamento ============ La soluzione di crittografia dei parametri qui mi è stata consigliata da uno dei nostri addetti alla sicurezza. Ne ho preso uno da asporto che non avevo considerato su questa soluzione - url infranti - e userò quello così come il problema di manutenzione creato da questa soluzione per discutere del tempo necessario per applicare le regole di accesso in un modo meno stopgap.

    
posta avgvstvs 16.07.2012 - 15:24
fonte

5 risposte

12

Buona domanda! Grazie per aver elaborato la minaccia che stai cercando di difendere. Ho modificato la mia risposta di conseguenza.

Riepilogo. La tua difesa principale dovrebbe essere controllo di accesso . È necessario limitare quali utenti possono visualizzare quali pagine. Dettagli sotto.

Controllo dell'accesso nelle applicazioni web. Ciò che devi fare è controllare che l'utente sia autorizzato ad accedere ai dati che stai per mostrare su una pagina, prima di consentire loro di vedere quei dati. Questo fondamentalmente si riduce al controllo degli accessi: vuoi controlli che limitino quali utenti possono visualizzare quali dati, in base ad alcuni criteri di autorizzazione.

Sembra che tu abbia una sequenza di pagine, una per ciascun agente:

http://www.example.com/agent/?producerId=12345
http://www.example.com/agent/?producerId=12346
http://www.example.com/agent/?producerId=12347
...

dove producerIds (agentIds) sono potenzialmente ipotizzabili o prevedibili. Si desidera assicurarsi che l'agente 12345 possa visualizzare http://www.example.com/agent/?producerId=12345 ma non nessuna delle altre pagine. OK.

Questa è una situazione standard della palude e la difesa standard della palude è: controllo dell'accesso.

Per implementare il controllo degli accessi, si codifica l'applicazione Web in modo che ogni pagina controlli se l'utente è autorizzato a visualizzare quella pagina prima di consentire all'utente di visualizzare quella pagina. Ad esempio, per la pagina sopra elencata, la logica che implementa quella pagina dovrebbe verificare l'identità dell'utente attualmente connesso. Se l'id dell'utente che ha effettuato il login corrisponde a producerId del parametro page, mostrerà loro le informazioni. Se l'ID non corrisponde, non gli mostri le informazioni: se è un altro utente, gli mostri una pagina di errore (con informazioni su come ottenere l'accesso), o se l'utente non ha ancora effettuato l'accesso, reindirizza a una pagina di accesso.

Questo non infrangerà i segnalibri. Non richiede modifiche al database, modifiche al livello di persistenza o controllo degli accessi basato sui ruoli. Richiede di avere un modo per cercare l'identità dell'utente attualmente loggato e associarlo con il proprio ID provider. Inoltre, se si desidera consentire a manager e supervisori di visualizzare i dati per tutti gli altri agenti, è necessario un modo per cercare l'utente attualmente connesso e determinare se sono manager o supervisori o meno. Se si desidera consentire solo al manager / supervisore dell'agente di visualizzare la propria pagina (non tutti gli altri gestori / supervisori), è necessario disporre di un modo per determinare il manager / supervisore di ciascun agente. Questi sono requisiti basilari e minimi; è difficile capire come puoi evitarli.

Come sottolinea correttamente @symbcbean, questo è un errore molto frequente che si riscontra spesso nelle applicazioni web. Un esempio tipico potrebbe essere un sito che utilizza un valore di parametro ipotetico per identificare una risorsa e non autentica adeguatamente l'utente. Ad esempio, supponiamo che agli ordini venga assegnato un numero di ordine sequenziale:

https://www.example.com/show_order.php?id=1234
https://www.example.com/show_order.php?id=1235
https://www.example.com/show_order.php?id=1236
...

e supponiamo che chiunque conosca l'URL possa visualizzare l'ordine. Sarebbe un errore, perché significa che chiunque conosca (o indovina) il numero dell'ordine può visualizzare l'ordine, anche se non è autorizzato a farlo. Questo è uno dei I primi dieci di OWASP rischi per la sicurezza delle applicazioni web: Riferimenti agli oggetti diretti non sicuri . Per ulteriori informazioni, consiglio di leggere le risorse disponibili su OWASP. OWASP ha un sacco di grandi risorse sulla sicurezza delle applicazioni web.

Altri commenti. altri hanno suggerito di utilizzare SSL. Sebbene ciò non impedisca la manomissione dei parametri, è una pratica di sicurezza generale che difende da altri tipi di problemi. L'uso di SSL è semplice: basta configurare il sito Web per utilizzare https, anziché http (e idealmente, abilitare HSTS e impostare il secure bit su tutti i cookie).

Inoltre, spesso è meglio evitare di memorizzare informazioni riservate nei parametri URL, a parità di tutti gli altri. È possibile memorizzare le informazioni riservate nello stato di sessione o nel database.

    
risposta data 16.07.2012 - 20:29
fonte
6

In breve: Non crittografare i parametri URL, utilizzare un separato look-up .

Inoltre, l'utilizzo di HTTPS è fondamentalmente non negoziabile se si desidera una misura della sicurezza delle applicazioni Web. È obbligatorio nel 2015. Mettiti comodo con TLS 1.1 +.

Che cosa vogliono fare gli sviluppatori

Checosadovrebberofareglisviluppatori

    
risposta data 30.09.2015 - 15:51
fonte
3

but we needed to prevent sales agents from peeking on each other's leads

Questo implica piuttosto che il client è un browser - stai inviando la chiave come testo chiaro ad un certo punto?

Il polinomio è corretto, dovresti usare SSL. Questo non risolverà il problema degli utenti che digitano valori adiacenti a un URL che assomiglia a qualcosa del tipo:

https://www.example.com/show_order.php?id=1234
https://www.example.com/show_order.php?id=1235
https://www.example.com/show_order.php?id=1236
...

È abbastanza possibile generare un token di autenticazione lato server in base ai parametri che devono essere presentati per convalidare la richiesta. Idealmente dovresti usare un codice di autenticazione dei messaggi (MAC) per questo, ma un hash funzionerebbe anche se stai attento. per esempio. in PHP ...

 print "<a href='show_order.php?id=" . $id . "&valid=" . md5($id . crypto_key()) . "'>...

Che è validato semplicemente da:

if ($_GET['valid'] != md5($_GET['id'] . crypto_key()) {
   die('not authorized');
}

Qui crypto_key() restituisce una chiave crittografica statica (generala estraendo, diciamo, 128 bit da /dev/urandom e memorizzandola nel database).

Tuttavia, devi ancora controllare l'accesso al codice che genera l'URL.

    
risposta data 16.07.2012 - 17:27
fonte
2

Ecco la mia soluzione

$id=1234;
$en_id = encrypString( $id);

e creo l'url come

https://www.example.com/show_order.php?id=$en_id

l'url sarà simile a

https://www.example.com/show_order.php?id=9muEYh4lShFDeCnXqoNpxucs42Fuz5Nexq1IUGWYEffffe88yRbJu

e sull'altro lato decritto

$en_id= decryptString($_GET['id']);

le funzioni per crypt e decrypt sono

function encrypString($plaintext) {
         # --- ENCRYPTION ---

        $key = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3");//change this

        # show key size use either 16, 24 or 32 byte keys for AES-128, 192
        # and 256 respectively
        $key_size =  strlen($key);
        //echo "Key size: " . $key_size . "\n";


        # create a random IV to use with CBC encoding
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM);

        # creates a cipher text compatible with AES (Rijndael block size = 128)
        # to keep the text confidential 
        # only suitable for encoded input that never ends with value 00h
        # (because of default zero padding)
        $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key,
                                     $plaintext, MCRYPT_MODE_CBC, $iv);

        # prepend the IV for it to be available for decryption
        $ciphertext = $iv . $ciphertext;

        # encode the resulting cipher text so it can be represented by a string
        $ciphertext_base64 = base64_encode($ciphertext);

        return  rawurlencode($ciphertext_base64);//important rawurlencode for + symbol in url

    }


decryptString($ciphertext_base64) {
        # --- DECRYPTION ---

        $key = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3");//change this

        # show key size use either 16, 24 or 32 byte keys for AES-128, 192
        # and 256 respectively
        $key_size =  strlen($key);
        //echo "Key size: " . $key_size . "\n";

        # create a random IV to use with CBC encoding
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM);

        $ciphertext_dec = base64_decode($ciphertext_base64);

        # retrieves the IV, iv_size should be created using mcrypt_get_iv_size()
        $iv_dec = substr($ciphertext_dec, 0, $iv_size);

        # retrieves the cipher text (everything except the $iv_size in the front)
        $ciphertext_dec = substr($ciphertext_dec, $iv_size);

        # may remove 00h valued characters from end of plain text
        $plaintext_dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key,
                                    $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);

        return rawurldecode($plaintext_dec);
    }
    
risposta data 18.07.2014 - 00:16
fonte
1

Per prevenire la manomissione dei parametri, ho sempre inviato un hash con i valori del testo normale.

es. prendi questo url che vuoi proteggere

https://www.mysite.com/somepage?param1=abc&param2=xyz

Sul server, il tuo modello ha hash tutti i valori di url con un salt segreto

string salt = "A1B2C3D4...";
string param1 = "abc";
string param2 = "xyz";
string hash = YourFavoriteHashingAlgorithm(param1 + param2 + salt);
// result hash = "Y83YMB38DX83YUHFIEIGKDHSEUG"

quindi invii questo hash insieme agli altri valori di url

https://www.mysite.com/somepage?param1=abc&param2=xyz&hash=Y83YMB38DX83YUHFIEIGKDHSEUG

Ora, quando ricevi una richiesta a questo URL, prendi di nuovo i parametri che hai presentato e li digita attraverso lo stesso algoritmo. L'hash che hai appena generato deve corrispondere all'hash che ti viene presentato, altrimenti invia un risultato 400 "Bad Request"!

La cosa bella è che i tuoi parametri sono ancora leggibili dagli umani, e tutta la tua logica di validazione esistente può rimanere la stessa.

    
risposta data 01.12.2017 - 03:02
fonte

Leggi altre domande sui tag