Go Down

Topic: [da testare] Libreria per autenticazione sicura (Read 3925 times) previous topic - next topic

lestofante

Jan 30, 2014, 11:58 pm Last Edit: Jan 31, 2014, 11:23 am by lesto Reason: 1
Ciao,
visto che ogni tanto le notre applicazioni sono esposte via internet, è bene proteggerle con una password.
Però mi sono accorto che spesso le guide fanno "viaggiare" le password in chiaro, o peggio le "criptano" in base64, facendo intender che sia più sicuro.

Inutile sottolineare che non sia così. E che il nostro povero arduino NON regge la criptazione SSL, e quindi niente HTTPS.

Quindi il sistema usato è molto semplice:
Un ipotetico client si collega, eventualmente inviando un userID.
Il server gli assegna un userID (se non presente) e un codice, e li spedisce al client (in chiaro).

Attenzione, il codice non è testato.
Lo metto quì per vedere a quanti interessa, domani sera spero di riuscire a fare qualche test.


la libreria necessita anche della libreria ArduinoMD5 che potete scaricare qui https://github.com/tzikis/ArduinoMD5/

Code: [Select]
unsigned long code1 = auth.askToken(userID, userPSW); //userPSW è la password CORRETTA per l'utente, che arduino deve conoscere

il client concatena (attenzione all'odine, e senza i +) userID+codice+password dopo di che fà l'MD5 della stringa ottenuta e la spedisce al server, oltre che il suo userID

Il server controlla che la stringa md5 sia valida

Code: [Select]
boolean isValid = auth.check(userID, responseMd5);

ATTEZIONE: il codice NON sarà più valido

a questo punto, il server potrebbe generare un nuovo codice chiamando di nuovo askToken() (magari con un userID fittizio/random per mischiare un pò le acque) e mantenere così attiva una sessione "sicura"; anche se l'attaccante intercetta il traffico, nel peggiore dei casi sarà in grado di eseguire UNA sola chiamata spacciandosi per noi. Notare che la debollezza dell'MD5 (le collisioni) sono aggirate dalla generazione di un codice nuovo ad ogni chiamata.

Uno UserID può avere più di un token valido alla volta, e di default un token "scade" dopo 10 minuti. Per settare un valore di timeout arbotrario IN MILLISECONDI usare
Quote
AuthManager auth(10 * 1000UL); //in questo caso timeout di 10 secondi
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

leo72

Aspe, spiega.
Chi fornisce le password?

Parli di codici non più validi, ti tieni una lista di codici scaduti?

Perché codici e password? Che differenza c'è nella tua idea fra il primo ed il secondo?

Scusa le domande, ma mi interessa capire bene  :P

gpb01

#2
Jan 31, 2014, 09:46 pm Last Edit: Jan 31, 2014, 10:26 pm by gpb01 Reason: 1
Leo è una tecnica che uso molto spesso anche io quando non è richiesta un'altissima sicurezza ...

In particolare io uso la seguente tecnica :

1. il client chiede al server un codice che varrà solo quella volta (è generato random)
2. il client conosce una sua parola chiave proprietaria che conosce anche il server
3. il client prepara il messaggio che deve mandare la server dopo di che ci aggiunge in punti che solo lui e il server conoscono (es. in testa e in coda, in mezzo, ...) il codice e la parola chiave e del tutto calcola l'MD5
4. il client trasmette al server il messaggio e l'MD5 NON il codice (tanto il server lo ha generato lui) e NON la parola chiave che il server deve sapere.
5. Il serve riceve calcola allo stesso modo l'MD5 e li confronta ... e così autentica il messaggio

Questo ha due vantaggi ...

1. per chi NON ha accesso al SW, il codice che cambia ogni volta sicuramente complica la vita
2. per chi HA accesso al codice ... comunque non ha la parola chiave e quindi comunque non è in grado di calcolare l'MD5

Il punto 2 è importante se "distribuisci" il prodotto e quindi, chi lo compra, può vedere il codice (la mia parte server è scritta in PHP ... vero che l'ho offuscata ... ma anche quello spesso lascia il tempo che trova) ma ogni cliente usa la SUA parola chiave che gli altri non conoscono ;)

Oh, ripeto, è per dove non serve una grandissima sicurezza ... altrimenti si passa a generatori HW di numeri casuali e di OTP :)

Guglielmo
Search is Your friend ... or I am Your enemy !

lestofante

esatto, sono "Token one time" generati a partire da una password comune decisa a priori, ed un codice generato dal server (per evitare che un client truffaldino riutilizzi una combinazione MD5+codice sniffata, nel mio caso visto che ilreinvio del codice da client a server non è necessario bisogna sniffare le 2 richieste fatte dal client, la prima in cui il server da il codice, la seconda in cui il client invia l'MD5)

poi la sicurezza è quella che è, ci mancherebbe, ma almeno la password è al sicuro da "sniffatori", per esempio se si usa la rete aziendale o wifi NON nostre.. (uso la millis() per generare codici! quindi se hai pazienza ~50 giorni e hai sniffato a priori.. certo se componessi il codice con DUE long...)

In teoria il codice è da usare in combinazione con una libreria che interpreta le richiete HTTP (anzi, quasi REST! GET, POST, PUT, DELETE), la rilascio a breve... datemi un'oretta  :smiley-mr-green:
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

leo72

Ah, ok. Sono protocolli di scambio di autenticazione.
Con la spiegazione di Guglielmo ne ho avuto la conferma.
Non avevo capito bene dalle spiegazioni iniziali  :smiley-sweat:


(uso la millis() per generare codici! quindi se hai pazienza ~50 giorni e hai sniffato a priori.. certo se componessi il codice con DUE long...)

Potresti inserire sul timer 2 una ISR che ti incrementa un altro long, magari con frequenza differente rispetto a quella usata sul timer 1.
Oppure, altra soluzione, potresti usare un long long. Il compilatore supporta questi numeri a 64 bit (ricordi le prime versioni della swRTC?), anche se, dovendoli gestire via software, si appesantisce un pò il codice. Ma per avere giusto un timestamp, puoi pagare il dazio di quei 2/300 byte in flash di più  ;)

lestofante

posso usare il long long, ma sarebbe complesso visto che per ora faccio codice = millis(), dovrei creareun sistema ad hoc... un contatore di overflow di millis(), per esempio :) se millis() < lastMillisUsed allora il secondo codice++
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

leo72

Un sistema ad hoc è banale. Ti crei una piccola routine ISR e la agganci al timer 2, impostato per overflow da 1 ms. Lì dentro metti un counter++, con counter dichiarato unsigned long long. Stop.  ;)
Sono 5 righe di codice, tra setup del codice e ISR.

lestofante

ma perdo un timer..

ps. ho un problema grosso. Se metto una String dentro una struttra sembrano nascere problemi di RAM.

Il che è strano, in teoria la String ha dimensione fissa, tranne il PUNTATORE alla stringa, che però essendo chissà dove non dovrebbe dare probelmi. l'uso di ram credo esssere molto basso, ora provo
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

leo72

Non so se la perdita di un timer sia un problema oppure no, questo devi giudicarlo tu.
Un'alternativa ci sarebbe.... hackeri il core e metti nella ISR del timer 0 un'aggiunta al codice originale con cui incrementi una long long. E ti fai una millis2.

Oppure usi il watchdog ma hai un intervallo minimo di soli 16 ms

lestofante

nono, l'idea è che deve essere semplicee senza side-effect.

Se prioprio devo, uso il sistema del +1 se rilevo che millis() è < dell'ultimo valore usato. Se ci pensianchese perdo un overflow, il peggio che può capitare è un token non scaduto (se è generato poco prima dell'overflow, e il secondo overflow siè verificato da poco) main tal caso non è un grossissimo problema REALE, certo uno smacco dal puntodi vista teorico.

Mi potete dare una mano a scrivere il primo post in modo che sia "capibile"?  :smiley-mr-green:

Anche per la stesura del codice, ho preferito eliminare brutture* ma fare in modo che fosse un esercizio di stile.
*(tranne l'uso di una String, ma rimedierò se necessario)

Lo faccio perchè così sperodi invogliareun pò a leggere il codice, certo non è un codice da novellino (doppi puntatori, liste, *alloc)

comunque ho appena testato e finito il parser HTTP, ora lo linko (anche questo un bel esercizio di stile e macchina a stati)
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

PaoloP

Non puoi usare microseconds() come secondo long e lo concateni con millis()?

lestofante

esiste una probabilità di collisione più alta che facendo il +1 ad ogni overflow rilevato,in oltre non aggiunge niente di più del +1.Certo è più semplice :)
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

leo72

Allora creati una routine ISR che agganci al watchdog e che incrementa una variabile, stile millis.
Hai una risoluzione di 16 ms ma difficilmente avrai collisioni dato che il watchdog è clockato da un risuonatore a 128 kHz indipendente.
Se ricordi, nella mia libreria pRNG uso proprio le tolleranze di questo risuonatore e le differenze con il clock principale per leggere ad intervalli regolari il registro di un timer e prelevare entropia. In questo modo, anche all'avvio iniziale, ho sempre una differenza seppur minima.


ricdata

Il tempo è denaro, ma il denaro non è tempo.

Go Up