2014-04-07 12 views
7

Ho bisogno di token unici per gli utenti memorizzati nel mio DB. Nel momento in cui genera un token, lo controllo per l'univocità nel DB prima di utilizzarlo. È un test che devo effettivamente eseguire o sto perdendo tempo?Rails, ruby: è necessario verificare SecureRandom.urlsafe_base64 per l'unicità dei token?

Ho guardato il Ruby 2.0.0 API for SecureRandom e non chiarisce se posso "fidarmi" dell'unicità o meno.

So che nessun valore casuale può essere davvero "unico" e c'è un numero finito di possibilità. Ma con 32 bit di valori esadecimali mi sento sicuro di non incappare mai più nello stesso valore nella mia app, ma volevo chiedere se qualcuno sapeva di un "pasticcio" con questa situazione.

Un'altra considerazione sta usando SecureRandom.uuid ma che sarà essenzialmente la stessa situazione.

# usage 
user.password_reset_token = Generator.unique_token_for_user(:password_reset_token) 

# Performs DB query to ensure uniqueness 
class Generator 
    def self.unique_token_for_user(attribute) 
    begin 
     token = SecureRandom.urlsafe_base64(32) 
    end while User.exists?(attribute => token) 

    token 
    end 
end 

risposta

7

SecureRandom.uuid genera UUID. Un UUID è lungo 128 bit e può garantire univocità nello spazio e nel tempo. Sono progettati per essere unici a livello mondiale, a differenza di urlsafe_base64. Vedi RFC4122.

+0

Anche la risposta inviata da @tompave è valida. Tuttavia, l'uso del generatore SecureRandom.uuid non richiede alcun lavoro aggiuntivo, quindi lo contrassegno come la migliore soluzione per la mia particolare domanda (il modo "garantito" di token unici). La specifica UUID 4 "dovrebbe" avere anche 122 bit casuali (da quello che ho letto) quindi non è solo unica, ma è anche sicura in quanto gli utenti non possono facilmente "indovinare" un altro UUID. –

4

No, non vedrai un duplicato nella tua vita.

32 è la lunghezza (in byte) del numero casuale generato prima di venire convertito di una stringa base64 urlsafe, così probabilità di un duplicato sono circa 1 a 10'000'000'000'000'000'000' 000'000'000'000. Questo è 10e31 e l'universo ha solo 43e17 secondi.

4

Non garantisce l'univocità ma, come dice svoop, è estremamente improbabile che si ottenga lo stesso risultato due volte.

Il mio consiglio è: se tutto ciò che serve sono casuali, unici e difficili da indovinare gettoni, e non si dispone di centinaia di migliaia di utenti, quindi utilizzarlo senza preoccuparsi.

Se assolutamente desidera gettoni unici (ad esempio v'è un certo obbligo di legge), poi unire un campo univoco associato con l'utente (ad esempio l'e-mail utente) e un sale casuale e hash il risultato.

Un'implementazione ingenuo potrebbe essere:

require 'securerandom' 
require 'digest/md5' 


def generate_user_token(user) 
    digest(user.email + random_salt) 
end 


def random_salt 
    SecureRandom.urlsafe_base64 
end 


def digest(string) 
    Digest::MD5.hexdigest string 
end 
+0

Questa è una buona soluzione. Tuttavia, sono andato con l'implementazione SecureRandom.uuid perché ciò richiedeva meno lavoro da parte mia pur garantendo univocità/sicurezza :) –

+0

Preferisco questa soluzione, molto più sicura. – JellyFishBoy

Problemi correlati