2009-09-08 14 views
7

Possiedo un'app che comunica con un server che utilizza l'autenticazione HTTP Digest.Utilizzo dell'autenticazione HTTP Digest su iPhone

Mi sembra che la gestione della "sessione" all'interno dell'iPhone sia una "scatola nera" per noi sviluppatori. È vero che non possiamo vedere come il framework gestisce/persiste le sessioni http?

Se sono solo in penombra, qualcuno vorrebbe spiegare come gestire l'autenticazione HTTP Digest sull'iPhone?

La mia corsa di base attraverso è:

  • effettua una richiesta a un URL protetto
  • Server invia un client 401
  • crea e persiste una credenziale, e lo passa al server
  • il server verifica le credenziali, completa la richiesta se verificato, invia un altro 401 se non.
  • fare una richiesta successiva per garantire url
  • richieste al server di nuovo l'autorizzazione ........

Questo funziona per le singole richieste, ma se faccio supplementari, le richieste successive, l'autorizzazione richieste al server ancora. Il server ha persistito una sessione per l'utente particolare, ma l'iPhone non sta effettuando una richiesta all'interno della stessa sessione per qualche motivo ... Pertanto, il server deve eliminare l'oggetto di autenticazione e crearne uno nuovo ogni volta che il client effettua una richiesta a un url protetto.

Sono sicuro che questo non è un comportamento corretto.

Se guardiamo a come un browser si comporta in questa situazione:

  • browser richiede dati da URL sicuro
  • server invia 401
  • browser richiede all'utente di credenziali, persiste, la trasmette al server
  • server verifica le credenziali, restituendo i dati se verificato, invia un altro 401 se non.
  • successive richieste fatte per proteggere gli URL non vengono richieste le credenziali perché il browser gestisce la sessione.

Sto creando NSURLCredential e lo sto persistendo all'interno di NSURLCrendtialStorage. Quindi, quando l'app riceve "didReceiveAuthenticationChallenge", recupero le credenziali dall'archivio e le restituisco, creando la credenziale se non esiste (alla prima richiesta).

Qualsiasi aiuto sarebbe molto apprezzato. Grazie.

risposta

3

Prima cosa, è dimenticare le sessioni HTTP, in quanto queste non interagiscono con i login attivi dell'autenticazione del digest (esiste una sorta di capacità di informazioni sulla sessione, ma è diversa).

Infatti, uno dei motivi principali per l'utilizzo di Digest, è di non dover utilizzare le sessioni solo per mantenere uno stato di accesso. Le sessioni sono pesanti e danneggiano la scalabilità.

Non posso dire con certezza quale sia il problema, ma so cosa controllare per primo, che è l'uso corretto di stantio e la corretta creazione di nonces.

Gli agenti utente possono gestire l'autenticazione senza richiedere all'utente se gli viene richiesto di gestire lo stesso nonce, o in un altro caso verrà in seguito (più facile da spiegare in questo ordine).

Se si ha lo stesso nonce utilizzato in ogni richiesta, lo user-agent continuerà ad usarlo insieme a "ha1" dall'utente/pass per richiedere risorse successive. Questo viene fatto preventivamente, quindi la sfida non accade mai.

Ovviamente, l'uso dello stesso nonce introduce un elemento di insicurezza, poiché gli attacchi di ripetizione diventano banali per chiunque possa annusare il traffico. Gli obblighi dovranno cambiare su base regolare.

Quindi, se si riceve una richiesta da un user-agent con un'intestazione di autorizzazione non valida, ma il motivo per cui non è valido è che il nonce è errato (sta utilizzando uno scaduto) quindi nella propria sfida includere "stale = true "(predefinito su false). Questo informa l'utente-agente che il motivo del rifiuto è il nonce è obsoleto (ovviamente anche le altre informazioni potrebbero essere sbagliate, ma ciò non importa in quanto non lo lascerai giocare in entrambi i modi).

Alla ricezione di tale stato = vero lo user-agent saprà che non è autorizzato, ma invece di richiedere l'utente (o lanciare un'eccezione se si tratta di un componente UI-less) riproverà i vecchi criteri con il nuovo nonce.

Non riesco a capire se questo sia ciò che ti sta influenzando, ma il modo in cui determinati aspetti e stoltezza sono determinati e segnalati è sicuramente la prima cosa che guarderei.

+0

Jasarien, prendo il segno di spunta nel senso che questo ti ha messo sulla strada giusta? (per la mia curiosità, e forse il beneficio di qualcun altro che trova lo stesso problema). –

1

Ho scritto un'app per iPhone con autenticazione HTTP e ho provato quello che descrivi. (La mia applicazione utilizza l'autenticazione di base invece dell'autenticazione digest, ma qui non fa una grande differenza.)

La causa del problema è sul lato iPhone. Al server è richiesto di rispondere con 401 se l'iPhone non invia le credenziali nell'intestazione della richiesta HTTP. E in effetti non lo fa anche se potrebbe facilmente una volta che la credenziale è memorizzata nella memoria delle credenziali.

Questo strano comportamento ha avuto un effetto grave sulla velocità dell'applicazione poiché ogni richiesta ha causato due round-trip al server anziché uno (il primo con stato 401, il secondo con 200).

ho risolto impostando manualmente le credenziali nell'intestazione richiesta HTTP:

NSString* credentials = [NSString stringWithFormat: @"%@:%@", usr, pwd]; 
const char* credentialsChars = [credentials cStringUsingEncoding: NSUTF8StringEncoding]; 
credentials = [CommunicationUtil stringBase64WithData: (const UInt8*) credentialsChars length: strlen(credentialsChars)]; 
NSString* authorizationHeader = [NSString stringWithFormat: @"Basic %@", credentials]; 

NSMutableURLRequest* request = 
    [[NSMutableURLRequest alloc] initWithURL: url 
     cachePolicy: NSURLRequestReloadIgnoringLocalCacheData 
     timeoutInterval: 15]; 

    [request setValue: authorizationHeader forHTTPHeaderField: @"Authorization"]; 

Ora la mia applicazione funziona molto bene ed è molto reattivo.

La soluzione sarà leggermente diversa per l'autenticazione digest. Ma avrai l'idea.

+1

L'autenticazione del digest sembrerà * molto * diversa. Se ASIHTTPRequest lo supporta già, lo userei invece di fondere qualche crittografia. –

+1

Secondo i documenti, ASIHTTPRequest fa, quindi andrei con il suggerimento di tc. Ti risparmio un sacco di mal di testa dal dover codificare tutte queste cose manualmente –

+0

Ho studiato i dettagli dell'autenticazione del digest e devo essere d'accordo: sono piuttosto scomodo da implementare. Calcolare gli hash MD5 è la parte più semplice. Gestire tutti i dettagli nell'intestazione HTTP è la parte difficile. Quindi sì: probabilmente è meglio provare ASIHTTPRequest. – Codo