2009-06-02 7 views
21

Ho uno scenario in cui gli utenti di un sito che sto costruendo hanno bisogno di inserire alcune informazioni di base in un webform senza dover effettuare l'accesso. Il sito è in fase di sviluppo con ASP.NET/C# e utilizza MSSQL 2005 per i suoi dati relazionali.Implementazione di URL di attivazione "monouso" sicuri e univoci in ASP.NET (C#)

Gli utenti riceveranno un'e-mail dal sito, fornendo loro un collegamento univoco per inserire le informazioni specifiche richieste. L'e-mail sarà molto simile allo stile di e-mail che riceviamo quando ci si registra per siti come i forum, che contiene un parametro URL univoco generato in modo casuale e specifico per un singolo scopo (come la verifica di un indirizzo email per un forum).

Le mie domande riguardano l'implementazione sicura di questo problema. Stavo considerando l'utilizzo di un GUID come identificatore univoco, ma non sono sicuro delle sue implicazioni nel mondo della sicurezza.

  1. È un GUID sufficientemente lungo in modo tale che i valori non possano essere facilmente indovinati (o forzati brute nel tempo)?
  2. La GUID di .NET è sufficientemente casuale nel senso che esiste una possibilità uguale di generazione di tutti i valori possibili nello "spazio chiave"?

  3. Se l'utilizzo di un GUID è un approccio accettabile, il sito deve quindi reindirizzare le informazioni tramite riscrittura degli URL o associando le informazioni in un datatable al GUID come riferimento?

  4. L'utilizzo di una riscrittura dell'URL nasconderà la vera origine dei dati?

  5. Devo considerare l'utilizzo di SELECT NEWID() di TSQL come generatore GUID rispetto all'implementazione .NET?

  6. Sono completamente in errore con il mio approccio a questo problema?

Molte grazie,

Carl

risposta

12
  1. Sì, 2 è abbastanza lungo.
  2. No, le implementazioni GUID sono progettate per generare GUID univoci anziché casuali. È necessario utilizzare un generatore di numeri casuali cryptographically secure (ad esempio RNGCryptoServiceProvider) per generare 16 byte casuali e inizializzare una struttura Guid con quella.
  3. Sì, è un approccio accettabile nel complesso. Entrambi funzioneranno.
  4. Sì, se non si danno gli ulteriori indizi
  5. No, goto 2
  6. No, è abbastanza OK. Hai solo bisogno di utilizzare un generatore di numeri casuali crittograficamente sicuro per generare il GUID.
+0

Ci scusiamo, ma questo è veramente sbagliato e fuorviante - GUID non sono buoni per questo genere di cose, vedere la mia risposta qui sotto. – AviD

+0

GUID, nel senso di * identificativo univoco * non è particolarmente adatto (come ho detto in # 2). Ma non c'è nulla che ti impedisca di usarli come un numero a 128 bit. –

+0

Ma il fatto è che sono * non * numeri a 128 bit (anche se richiede 128 bit per memorizzarli). Di nuovo, troppo di ciò è statico o facilmente ipotizzabile. I GUID non hanno alcun uso negli identificatori sicuri. Ciò di cui l'OP ha bisogno è qualcosa di sicuro e abbastanza a lungo nel senso di "128 bit di casualità", che i GUID non sono, nemmeno vicini. – AviD

4

Si consiglia di utilizzare solo un numero casuale semplice, ad es. byte da RNGCryptoServiceProvider.GetBytes. I GUID non sono pensati per essere completamente casuali. Hanno dei bit fissi e alcune versioni usano il tuo indirizzo MAC. GetBytes ti dà anche la possibilità di usare più di 128 bit (anche se dovrebbe essere abbastanza).

Penso che sia meglio non inserire i dati dell'utente in un url. Sebbene HTTPS possa proteggerlo durante il transito, potrebbe comunque trovarsi nella cronologia del browser dell'utente o simili. È meglio usare POST e associare il numero casuale a una riga del database.

1

Innanzitutto, se possibile, limitare la forza bruta, limitando il throughput della query (ad esempio tentativi limitati per IP al secondo e tentativi totali limitati al secondo).

A seconda dell'algoritmo di generazione GUID, questa potrebbe non essere una buona idea. Mentre le implementazioni recenti dovrebbero essere "abbastanza buone di solito", ci può essere un sacco di prevedibilità ai valori. Implementazioni recenti come quella utilizzata in .NET applicano un hash, altrimenti hai campi chiaramente identificabili per l'indirizzo MAC e tempo trascorso dal boot. Tuttavia, i valori possibili sono limitati, quindi non hai veri 128 bit casuali.

Se la sicurezza è la priorità, sceglierei uno cryptographically strong random number generator e creare una stringa di caratteri casuali. Ciò rende Oyu indipendente da un algoritmo facilmente ipotizzabile (come un guid.ToString() è facilmente identificabile come tale) per il quale un attacco potrebbe essere scoperto nel prossimo futuro.

Se questi criteri vengono soddisfatti, non vedo alcun problema nell'avere la chiave nella stringa di query.

4

Potrebbe essere eccessivo, ma si potrebbe hash il proprio indirizzo di posta elettronica con SHA1 utilizzando il proprio guid (NewGuid va bene) come hash salt e posizionarlo nell'URL. Quindi, quando arrivano alla tua pagina, puoi chiedere loro il loro indirizzo email, recuperare il guid e ricalcolare l'hash per convalidare. Anche se qualcuno dovesse sapere quali indirizzi e-mail provare, non sarebbero mai in grado di generare una collisione hash senza conoscere la guida con cui è stato salato (o ci sarebbero voluti molto tempo :). Ovviamente, dovresti salvare la loro e-mail e l'hash salt hash nel database.

+0

Sebbene quanto sopra abbia risposto in modo tecnico alle mie domande direttamente, adoro la tua idea di implementazione. Dopo aver riflettuto ho expaneded su di esso un po ': URL = SHA1 (e-mail + randomPass + sale) serverHash = SHA1 (e-mail + randomPass) colonne della tabella: serverHash (chiave primaria) sale Il randompass sarebbe anche essere inviato con l'url nell'email e utilizzato nel calcolo dell'URL originale quindi scartato. Credo che in questa implementazione non vengano memorizzate informazioni sensibili nel database.Il significato, anche se il databile non elaborato è stato esposto, non è stato possibile generare l'URL per forzare l'indirizzo e-mail – Tyst

+1

Felice di aiutare. Una nota sulla tua soluzione, ti apri a un nuovo caso d'uso poiché non puoi ricreare l'email. Cioè, l'utente richiede ed e-mail, non fa nulla con esso, ne richiede un altro e poi fa clic sul link nella prima e-mail (come sono sicuro tu sai, gli utenti fanno cose del genere :) Quindi, dovrai scadere ogni ServerHash mantenendo la data di invio dell'email nel DB e fornendo all'utente un tempo ragionevole per rispondere. –

+0

Sì, grazie. Me ne rendo conto Le e-mail e gli URL generati sono molto specifici del caso e generati per consentire agli utenti di risparmiare un po 'di soldi, quindi dovrebbero probabilmente usarli, ma implementerò anche un po' di gestione. – Tyst

11
  1. No, i GUID non sono completamente casuali e la maggior parte dei bit è statica o facilmente ipotizzabile.
  2. No, non sono casuali, vedere 1. C'è in realtà un numero molto piccolo di bit che sono in realtà casuali, e non casualmente forte crittograficamente.
  3. Non lo è, vedere 1 e 2.
  4. è possibile, ma non è necessario ... vedere la mia soluzione alla fine.
  5. No, vedere 1 e 2
  6. Sì.

Cosa si dovrebbe utilizzare al posto di un GUID, è una crittografia forte generatore di numeri casuali - utilizzare System.Security.Cryptography.RNGCryptoServiceProvider, per generare lungo (ad esempio, 32 byte) stringa di dati, quindi base64 encode che.
Inoltre, supponendo che si tratti di una sorta di registrazione con dati sensibili, si vorrebbe limitare la validità del collegamento, ad esempio 60 minuti o 24 ore, a seconda del sito.
È necessario mantenere una mappatura di questi valori per gli utenti specifici. Quindi è possibile presentarlo automaticamente con il modulo appropriato secondo necessità. Non è necessario eseguire la riscrittura url, basta usarlo come identificatore dell'utente (in questa pagina).
Naturalmente, non dimenticate questo URL deve essere HTTPS ...

Btw, solo una nota - la sua buona pratica di mettere una qualche forma di testo nella e-mail, spiegando che gli utenti sognerei cliccare sui link contenuti in email anonime, e tipicamente il tuo sito non invierà, e non dovrebbero mai inserire la loro password dopo aver cliccato su blablabla ....

Oh, quasi dimenticato - un altro problema che dovresti considerare è che cosa succede se l'utente desidera ricevere diverse e-mail, ad es. i colpi si registrano più volte. Può farlo più e più volte e ottenere molti URL validi? È valido solo l'ultimo? O forse lo stesso valore si risente più e più volte? Naturalmente, se un utente anonimo può inserire una richiesta per questa e-mail, allora il DoS potrebbe diventare un problema ... per non dire che se inserisce la sua e-mail, può inserire anche un indirizzo casuale, inondando alcuni poveri shmuck posta in arrivo e la possibilità di inserire il proprio server di posta nella lista nera ...
Nessuna risposta corretta, ma deve essere considerata nel contesto dell'applicazione.

-1

creare una tabella nel database con un linkID e una colonna Datesent, durante la generazione del collegamento, inserire insert DateTime.Now nella tabella e restituire linkId, impostare il linkID come parametro querystring su activationLink. Al caricamento della pagina di attivazione è possibile recuperare il linkId e utilizzarlo per evocare una procedura memorizzata che restituirà la data quando viene passato il corrispondente linkId come parametro, quando si ottiene la data indietro è possibile aggiungere per quanto tempo il collegamento rimarrà attivo da usando .AddDays() /. AddMonths sono i metodi C# per datetime. quindi confronta la data in cui sei tornato con la data di oggi. se ha passato la sua durata di giorni o mesi di dare un messaggio di errore o continuare e visualizzare il contenuto della pagina. Immagino che tu mantenga il contenuto della pagina in un pannello e lo imposti = "false" quindi rendi il pannello visibile = "true" se la data è ancora all'interno del range.

Problemi correlati