2010-11-29 12 views
24

Sono interessato a come implementare un sistema di accesso tra domini condivisi, nonché le best practice e le precauzioni di sicurezza da adottare. Se hai familiarità con 37Signals, probabilmente sei abituato a utilizzare un meccanismo di autenticazione universale condiviso per il quale non devi effettuare successivamente il login se utilizzi la navigazione di primo livello per un prodotto diverso. Mi piacerebbe implementare qualcosa in modo simile.Come creare un servizio di accesso condiviso su più domini?

La cosa più vicina che ho trovato online è la voce di Wikipedia su un Central Authentication Service e la risposta a Cross Domain Login - How to login a user automatically when transfered from one domain to another, che potrebbe essere leggermente diversa in questo caso.

Ho ispezionato i cookie di sessione per capire cosa stanno facendo nel processo. Inizialmente, ogni link prodotto ha un uristub "goto", vale a dire:

https://MY_COMPANY.campfirenow.com/id/users/[int_identifier]/goto

Utilizzando Firecookie e la scheda NET in Firebug, sono in grado di vedere i cookie impostati e il redirect che si verificano nel processo. Il goto URL spara un reindirizzamento 302 a:

https://MY_COMPANY.basecamphq.com/login/authenticate?sig=[BASE64_ENCODED_AND_ENCRYPTED_DATA]

l'identificatore di sessione viene ricreato, molto probabilmente a scopo di CSRF. Alcuni dei dati nei biscotti così come il parametro GET sig stati parzialmente decifrato utilizzando base64_decode al seguente:.

// sig GET param 
array(2) { 
    [0]=> 
���ף�:@marshal_with_utc_coercionT7�z��<k��kW" 
    [1]=> 
    string(18) "���k�<kn8�f���to��" 
} 

// _basecamp_session cookie session param 
string(247) { 
:_csrf_token"1Sj5D6jCwJKIxkZ6oroy7o/mYUqr4R5Ca34cOPNigqkw=:session_id"%060c0804a5d06dafd1c5b3349815d863" 
flashIC:'ActionController::Flash::FlashHash{: 
@used{: auth{" 
       MY_COMPANY{: 
         user_idi�3 
:identity_idi�W����������s�]��:�N[��: 

߾"

La codifica è rompere il blocco di codice Grazie per il vostro aiuto!

+0

Un servizio di accesso condiviso preconfigurato come OpenID, Facebook, OAuth o Google può funzionare per voi? O, hai assolutamente bisogno del tuo servizio di accesso condiviso? – Flipster

risposta

49

Penso che la chiave nella vostra Q sia dove si scrive "per cui non è necessario effettuare successivamente il login se si utilizza la navigazione di primo livello per un prodotto diverso".

Spiegherò: Si desidera essere in grado di passare da site1.com a site2.com e lasciare che site2.com sappia che si è un utente che ha effettuato l'accesso tramite site1.com.

perché i cookie non sono condivisibili tra domini diversi (ad eccezione dei sottodomini ma suppongo che non si stia parlando di sottodomini) è necessario passare alcune informazioni sul collegamento a site2.com che consentirà di parlare con il proprio back- fine e sapere quale utente sei.

consente di iniziare con una soluzione ingenua e quindi risolvere il problema alcuni dei problemi che pone: supponiamo di avere una tabella utenti su alcuni DB di back-end e l'utente ha qualche ID. ora supponiamo che l'utente sia autenticato su site1.com e che sia utente 123 dal tuo DB. La soluzione più ingenua sarebbe chiamare site2.com/url/whatever?myRealID=123 e avere il controllo site2 per questo ID e "credere" all'utente che questo è davvero lui.

Problema: chiunque (anche un utente valido del sito) che vedrà il tuo collegamento può creare un collegamento con myRealID = 123 o provare altri valori per esso. e site2.com lo accetterà come tale utente.

Soluzione: non utilizzare ID ipotetici supponiamo di aggiungere alla tabella utenti un GUID univoco e se l'utente 123 ha una guida di 8dc70780-15e5-11e0-ac64-0800200c9a66, quindi chiama site2.com/url/whatever?myGuid= 8dc70780-15e5-11e0-ac64-0800200c9a66.

nuovo problema: bene anche se sarebbe molto improbabile che qualcuno indovinerà il GUID per l'utente del suo GUID può ancora essere dirottato da un uomo medio che vede questo link e qualcuno otterrà il GUID può usarlo per sempre.

Soluzione: utilizzare una chiave privata salvata sul server per firmare una stringa contenente i seguenti dati, il timestamp corrente, il sito di destinazione (ad esempio "site2.com") detto GUID, questa firma può essere tradotta in dicendo "Questa è una prova che questo link è stato creato dal sito in quel momento per l'utente che ha questo GUID autenticato da questo dominio" e lo invia a site2.com insieme a timestamp e GUID. Ora quando site2.com ottiene il link, può assicurarsi che sia firmato correttamente e se qualche intermediario o utente originario proverebbe a cambiarlo in qualsiasi modo (o modificando l'ora o il GUID), la firma non corrisponderebbe e sito2. com rifiuterà di autenticare l'utente.

Un ultimo problema: se il collegamento è intercettato da un intermediario, può ancora usarlo se da qualche altra macchina.

Soluzione: aggiungere un nonce ai parametri passati. Il nonce è solo un numero casuale che il tuo sistema di autenticazione dovrebbe assicurarsi che non ti permetta di autenticarti con questo numero più di una volta (da cui quindi il nome N (umber) -ONCE). Nota che questo significa che ogni link che crei su site1.com che porta a site2.com dovrebbe avere un nonce distinto che deve essere salvato sul back-end per una successiva convalida.

perché non si desidera continuare ad aggiungere record a questa tabella nonce per sempre è consuetudine decidere che tale collegamento è valido solo per un certo periodo di tempo dopo la sua creazione. e così puoi creare record nonce che sono più vecchi di questo limite di tempo.

Spero che questo sia lo schema che cercavi. È possibile che mi sia sfuggito qualcosa, ma quelle sono le linee guida di base, utilizzare una firma per dimostrare l'autenticità dei dati nel link e utilizzare un nonce per prevenire gli attacchi di middleman. Vorrei anche raccomandare l'uso di HTTPS per questi collegamenti, se possibile.

Eyal

+1

Per implementare ulteriormente le chiavi condivise: aggiungere le vars di configurazione contenenti una coppia di chiavi pubblica/privata per ciascun dominio nel sistema di accesso condiviso. Se il metodo di verifica della firma è uguale su tutte le caselle, è possibile verificare le firme e persino utilizzare mcrypt() o una libreria equivalente per trasferire dati crittografati a due vie per una maggiore sicurezza in aggiunta alla firma di verifica (laddove una firma è essenzialmente un checksum dei dati). –

+0

Perché non utilizzare solo il nonce (collegato all'ID di sessione sul back-end)? Quello che intendo è semplicemente creare un token (forse una scadenza di 1-2 minuti, utilizzabile una sola volta) che è collegato all'ID di sessione sul back-end, quindi quando lo uso su site2 il server può prendere l'id di sessione dal db, cancellare il token e inviare il cookie al browser, dando al browser la stessa sessione che aveva su site1. Quali svantaggi ha questo approccio? – mettjus

+0

almeno una differenza sarebbe che su ogni tentativo di hacking dovresti andare al DB facendoti costare di più, ma solo verificare che i dati siano firmati correttamente e poi andare al DB solo se è effettivamente corretto firmato. – epeleg

0

hai provato qualcosa di simile Charles ad annusare ciò che viene inviato avanti e indietro? potrebbe essere in grado di abbattere ulteriormente le cose per voi.

come menzionato da FlipScript, forse u cantare OAuth/OpenID potrebbe essere una soluzione per te?

0

Date un'occhiata a Jasig CAS http://www.jasig.org/cas. Penso che farà quello che vuoi. È open source e ha un numero di plug-in che consente di autenticare l'uso di più fonti di autenticazione e da più domini/lingue.

1

Consentire agli utenti di utilizzare la propria soluzione facebook/yahoo/gmail/openID è un inizio, ma ciò non risolve la soluzione di implementare o utilizzare la propria soluzione.

Dopo aver sviluppato e gestito un'implementazione in passato (alla fine ci siamo rivolti a SiteMinder, ma suppongo che tu non voglia il costo di un prodotto reale), penso che Eyal abbia un'idea molto buona, ma io 'd aggiungere un piccolo ritocco ad esso.

Al momento dell'autenticazione, generare un codice casuale (potrebbe essere un valore GUID, ma non statico per utente) che viene archiviato in una tabella transazionale insieme all'ID utente. Questo codice ha una durata massima (dovrai giudicare il valore di sicurezza per quel periodo di tempo).Il codice dovrebbe idealmente essere sottoposto a hash con il nome utente o crittografato e inviato come parte dell'URL.

4

Si potrebbe provare a implementare una soluzione Global Network Auto-Login à Stack Overflow.
C'è un post interessante sulla sua brillante implementazione di Kevin Montrose here.

Richiede Cookie, HTML5 localStorage, Javascript, Iframe e molti controlli di sicurezza, ma penso che ne valga la pena.

0

Perché non utilizzare l'ID aperto per questo scopo.

OperID sarà la soluzione ottimale per questo problema.

+0

Open ID è un buon modo per autenticarsi ma non risolve il problema di cross site, ovvero se usi l'Open ID per accedere a siteA.com hai ancora bisogno dei metodi sopra riportati per creare una situazione in cui ora sei anche collegato al sitoB.com se vuoi essere in grado di autenticare con i social network comuni puoi anche utilizzare la soluzione fornita da gigya.com (dove lavoravo fino a poco tempo fa) - ma ancora una volta - questo non risolve il problema di attraversare i domini che dovrai gestire da solo. – epeleg

0

Utilizzare Qualcosa come .NET Passport (IE. Windows Live Id) o il modo in cui Facebook lo ha fatto con le loro API, che possono essere viste apertamente.

Problemi correlati