Questo token CSRF generato sarebbe stato considerato crittograficamente strong?

2

Sto lavorando per migliorare la sicurezza di un'applicazione web esistente che al momento non ha implementato l'uso di token anti-CSRF, quindi spetta a me generarne uno, aggiungere campi nascosti e controlli, ecc. Un diritto di limitazione ora è che né i moduli openssl o mcrypt sono attualmente configurati sul server.

Ecco il mio codice di generazione di token:

$csrfToken = base64_encode(uniqid(mt_rand(100, 999) . microtime(), true));

Ho la sensazione che questo fornisca un token adeguato, ma non particolarmente strong, ma questo è il mio istinto personale. Qualcuno ha qualche suggerimento su come posso rafforzare la sicurezza di questo token senza l'uso delle funzioni mcrypt o openssl? Grazie!

EDIT: Questo è il modo in cui sto verificando il token dopo che il modulo è stato inviato, dove $ token è il token passato con la richiesta:

function validate_token($token) {
    return isset($_SESSION['csrfToken']) && $token === $_SESSION['csrfToken'];
}
    
posta hRdCoder 24.12.2014 - 22:56
fonte

4 risposte

3

Direi di no. Qui è un articolo interessante su un argomento simile.

Suggerirei:

  1. Uso di una funzione di hash (questo non aggiunge praticamente alcuna sicurezza da solo, ma rende i miglioramenti menzionati sotto molto più efficienti), ad es. %codice%
  2. Aggiunta di una costante segreta casuale lunga (ciò aggiunge sicurezza mentre la costante segreta rimane segreta - questo valore può essere letto molto facilmente nel server di hosting condiviso), ad es. %codice%
  3. Leggendo alcuni byte da $csrfToken = base64_encode(hash("sha256", uniqid(mt_rand(100, 999) . microtime(), true), true)); se questo è disponibile e aggiungendoli al valore di hash ( questo aggiunge sicurezza reale senza l'uso di estensioni PHP menzionate nel post di domanda), ad es. %codice%
  4. Aggiungi l'IP e la porta del client (questo migliora un po 'la sicurezza, specialmente se l'indirizzo IP del client non è noto all'attaccante), ad es. %codice%
  5. Questo non migliora la sicurezza, ma rende più comprensibile l'algoritmo di generazione: rimuovi la roba uniqid () e sostituiscila con% $csrfToken = base64_encode(hash("sha256", "nS7W7@IEPJ~6&&vp#r>ziW-SGOC?s>!,.(s" . uniqid(mt_rand(100, 999) . microtime(), true), true)); , ad es. %codice%
  6. (Aggiunto più tardi) Aggiungi l'intestazione di richiesta HTTP /dev/urandom all'input della funzione di hash. Questo ha un duplice effetto sulla sicurezza - buona parte è che il token CSRF dipende anche dal cookie di sessione (quindi l'attaccante deve sapere / indovina il cookie di sessione della vittima per calcolare il token CSRF - nella maggior parte dei casi il cookie di sessione è più critico); la parte cattiva è che l'utente malintenzionato può provare a "indovinare" i cookie di sessione in base ai token CSRF salvati nella cronologia del browser. Per rendere questa ipotesi più complicata a livello di calcolo (a spese delle risorse del server), l'intestazione $handle = fopen("/dev/urandom", "rb"); $urandom_data = fread($handle, 16); if(strlen($urandom_data)!==16) exit("Unable to read /dev/urandom"); fclose($handle); $csrfToken = base64_encode(hash("sha256", $urandom_data . "nS7W7@IEPJ~6&&vp#r>ziW-SGOC?s>!,.(s" . uniqid(mt_rand(100, 999) . microtime(), true), true)); può essere cancellata da sola prima di aggiungerla, ad es. %codice%

P.S. Si noti che le stringhe di cifre a lunghezza variabile sono concatenate utilizzando separatori non a cifre (per evitare alcuni set di stringhe non equivalenti risultanti in valori concatenati equivalenti).

P.S.2 Sembra che ci sia una parentesi (" $handle = fopen("/dev/urandom", "rb"); $urandom_data = fread($handle, 16); if(strlen($urandom_data)!==16) exit("Unable to read /dev/urandom"); fclose($handle); $csrfToken = base64_encode(hash("sha256", $urandom_data . $_SERVER["REMOTE_ADDR"] . ":" . $_SERVER["REMOTE_PORT"] . "nS7W7@IEPJ~6&&vp#r>ziW-SGOC?s>!,.(s" . uniqid(mt_rand(100, 999) . microtime(), true), true)); ") mancante nel codice postale della domanda.

P.S.3 Maggiori informazioni sul significato della funzione hash crittografica qui. La funzione hash fa quanto segue:

  1. Aggiunge NO entropy - le funzioni sono deterministiche (la funzione di hash produrrà sempre lo stesso output da ogni particolare input). È importante capire che non viene aggiunta alcuna entropia (anche se la lunghezza della stringa è aumentata). SHA-256 dalla stringa "A" sarà lungo 32 byte, ma sarà comunque un valore ben noto (puoi solo Google questo hash in esadecimale per scoprire quanto sia popolare in realtà).
  2. Mescola e offusca (questa volta offusca non significa qualcosa di evitabile e insicuro) l'input - l'unico modo in cui l'attaccante può determinare l'input è indovinandolo. Fondamentalmente la funzione hash introduce un principio "tutto o niente": l'attaccante conosce l'intero input (e può verificarlo calcolando l'hash) o l'attaccante non sa quali parti dell'input che ha previsto siano corrette. Di conseguenza, la funzione hash consente di aumentare la sicurezza aggiungendo una costante segreta casuale lunga (passaggio 2 menzionato sopra), senza l'uso della funzione hash l'attaccante vedrebbe la costante in tutti i token CSRF osservati (quindi saprebbe quale sia la costante e che deve essere aggiunto).
  3. (Molto strettamente correlato a 2.) Rende l'attaccante in grado di spendere alcune risorse computazionali con ogni "ipotesi" dell'input della funzione di hash. Nell'articolo menzionato sopra l'hacker usa la GPU (scheda video), perché deve fare un gran numero di "ipotesi" e ciò richiederebbe molto tempo alla CPU. L'input più complesso (meno prevedibile) della funzione di hash è, più l'hacker di risorse computazionali deve utilizzare per indovinare l'input. Se l'autore dell'attacco dispone di risorse computazionali sufficienti a "indovinare" l'input della funzione di hash utilizzata per generare il token CSRF (come detto prima, la quantità di risorse di calcolo necessarie dipende dalla complessità / prevedibilità dell'input), può campionare l'input e iniziare a analizzare come è composto, identificare parti costanti ecc.

Per ulteriori informazioni sull'applicazione delle funzioni hash crittografiche sono rilevanti i seguenti articoli di Wikipedia: Funzione hash crittografica , Codice di autenticazione dei messaggi basato su hash .

P.S.4 Off-topic parziale: come accennato in precedenza, può essere facile per un utente malintenzionato estrarre il codice di costante e generazione attaccando l'ambiente di hosting condiviso.

    
risposta data 24.12.2014 - 23:45
fonte
1

No. Non sono uno sviluppatore PHP, ma ho trovato questo sulla funzione uniqID che stai utilizzando:

Pagina di manuale di UniqID

Attenzione

Questa funzione non crea stringhe casuali o imprevedibili. Questa funzione non deve essere utilizzata per motivi di sicurezza. Utilizza una funzione / generatore casuale crittograficamente sicuro e funzioni di hash crittograficamente sicure per creare ID sicuri imprevedibili.

Fai riferimento a questo thread sulla generazione di numeri casuali sicuri in PHP, poiché è al di fuori del mio scopo e in gran parte questo è ciò a cui si riferisce la tua domanda. Se stai ricevendo 128 bit di entropia, la codifica o il passaggio attraverso ulteriori funzioni di hash non sono in gran parte importanti.

    
risposta data 26.12.2014 - 22:10
fonte
0

Non cercare di reinventare la ruota e non provare a reinventare una soluzione per numeri casuali univoci. Se la tua lingua o il tuo framework forniscono una funzione per generare un UUID casuale, vai con quello. Potresti sapere cosa stai facendo, ma hai solo il debugging e il supporto. Il linguaggio o il framework ha una società o un'organizzazione dietro di esso per assicurarsi che lo facciano bene.

    
risposta data 28.12.2014 - 02:52
fonte
0

La risposta accettata sembra fornire olio di serpente insieme a buoni consigli.

Per la generazione di token CSRF in particolare, ci sono solo alcuni requisiti:

  • imprevedibile
  • una certa resistenza alla forza bruta
  • utilizza caratteri stampabili compatibili con la tecnologia web

Tutto ciò che devi fare per ottenere questo è generare abbastanza casualità crittograficamente sicuro per evitare un modesto tentativo di forza bruta (rispetto, ad esempio, al crack delle password offline) e poi codificare Base64.

Puoi vedere ciò che viene ampiamente utilizzato dalla comunità Clojure link come parte del middleware anti-contraffazione (impedisce CSRF).

(defn- new-token [] (random/base64 60))

La chiave è che la funzione random/base64 che viene chiamata qui utilizza la classe Java SecureRandom crittograficamente protetta sotto il cofano. Il 60 si riferisce a 60 byte di dati casuali da codificare Base64.

Questo è tutto.

Puoi ottenere lo stesso risultato procurando dati casuali da /dev/urandom .

Qui ci sono problemi con gli altri suggerimenti per l'algoritmo di generazione di token:

  • Uso di mt_rand - non usare affatto questo, non è adatto allo scopo qui ed è esattamente ciò che l'articolo collegato nella risposta accettata mette in guardia (ma poi la risposta accettata va per utilizzare mt_rand negli esempi di codice ...)
  • Uso di uniq_id - non crea stringhe imprevedibili o casuali, come per i documenti PHP
  • Usando una funzione di hash - riduce il set di caratteri, ma non aggiunge alcuna sicurezza. La codifica Base64 è più chiara sullo scopo e non implica funzionalità di sicurezza che semplicemente non sono presenti
  • Uso di una chiave segreta - In altri contesti le chiavi segrete sono fondamentali, in questo contesto ti forniscono semplicemente qualcosa che devi tenere segreto (non è una cosa facile da fare), aggiungendo complessità e difficoltà senza alcun vantaggio extra di sicurezza
  • aggiunta di IP client / porta / ecc. - Non rende il token più sicuro dei dati crittografici casuali, ma rende l'algoritmo più complicato e meno portabile
  • Uso del microtime - Non aggiunge alcuna sicurezza aggiuntiva, l'ora corrente è abbastanza prevedibile da essere forzata bruta. Se consideriamo mt_rand insicuro, sicuramente anche un timestamp.

In sostanza, qualsiasi cosa tu faccia che aggiunge complessità senza soddisfare i requisiti fondamentali, rende solo l'algoritmo:

  • Meno gestibili
  • Più difficile da capire
  • Più probabile che abbia un bug critico
  • Meno sicuro
risposta data 31.05.2017 - 12:23
fonte

Leggi altre domande sui tag