Controller Remoto (Domotica e non solo)

Salve a tutti,
voglio condividere con voi un progetto al quale sto lavorando da un po' e sembra funzionare molto bene:
si tratta di un web server completo in grado di permettere all'utente di tenere sotto controllo, modificare (accendere-spegnere) lo stato dei dispositivi collegati ai pin di Arduino da remoto. Il web server garantisce la sicurezza grazie all'utilizzo di una chiave generata in modo random che viene scambiata tra server e client. Esso permette inoltre di modificare da remoto la chiave in questione e il nome assegnato ai pin (che viene inoltre salvato sulla EEPROM per garantirne la permanenza anche in caso di spegnimento del dispositivo).

Allego il file .ino contenente il codice.

Sono ben accetti critiche e/o consigli!

Grazie a tutti!

controller_remoto_complete.ino (16.1 KB)

cosa hai usato come hardware?

Sia Arduino Ethernet che Arduino Mega 2560+Ethernet shield

Lo sai che non funziona come lo descrivi quello sketch vero?

  • prova a commutare tutti i pin
  • cambia le passw
  • entra con altri client in contemporanea e fai un test delle passw

provalo bene

  • I pin 2-3-4-5-6 non cambiano di stato
  • quando viene cambiata la pass funziona sia la nuova che la vecchia passw [default] admin
  • nella sicurezza ci sono 899 possibilità di tentativi per entrare
  • la passw [chiave] è visibile nell'url
  • Il cambio passw dovrebbe richiedere il
  1. nome della vecchia
  2. nome della nuova
  3. ripetizione della nuova
    Altrimenti qualunque utente te la cambia
  • una volta loggati con il primo client e accedendo con un secondo client ... il primo vieno buttato fuori
  • Tutte quelle var String pesano molto su un micro così piccolo, piuttosto usa progmem per righe ripetute, avrai spazio per aggiungere altre cosette

Siccome arduino non ha la potenza di elaborare una cifratura HTTPS// utilizza le cifrature che ti offrono i browser con codice 401 base64 (Basic access authentication) oppure a 128 bit (Digest access authentication) le informazioni transitano sempre nell'header e sono catturabili ... nel caso 64 sono piuttosto semplici, ma nel caso 128 in MD5 comincia ad essere un po' più impegnativo anche se catturo i char
Inoltre se spedisci un cookie al client che si è garantito l'accesso fa da "ciliegina sulla torta", un altro client che tenta l'accesso nonostante tu lo abbia già ... resta fregato, impostato poi alla chiusura del browser fa anche da logout automatico con conseguente distruzione del cookie [facoltativo](sempre meglio che chiuderlo in faccia dopo 5 minuti)
Puoi sempre mettere un timer su char c=client.read(); .. se entro 2 minuti non c'è nessun traffico di dati fai un logout

-I pin 2-3-4-5-6 cambiano di stato ma non viene reso visibile in quanto (come puoi notare dal codice) sono "pin il cui stato dipende da un ingresso"; questo significa che per verificare l'effettiva accensione (o spegnimento) del dispositivo collegato al pin in questione, viene riportato un riscontro derivante dal dispositivo stesso ad un pin di ingresso di arduino;
ad esempio:

 visualizzaRigaTabellaPinUscitaStatoDipendenteDaIngresso(client,pin2,nomePin2,pinA0)

indica che il riscontro relativo all'uscita "pin2" sarà dato dal pin A0, quindi la riga della tabella dipenderà da A0.

-Quando viene modificata la password, viene modificata quella relativa allo user del controllore, quella inizialmente impostata a "user"; per il momento la password dell'amministratore resta tale per consentire ad un amministratore di intervenire nel caso in cui l'utente dimentica la password o riscontra altri problemi.

-Consigli per rendere la chiave non visibile?

-La password può essere cambiata solo da un utente che ha già effettuato il Login e quindi ad un utente a cui è consentito farlo.

-Il problema dell'accesso multiplo è stato volutamente ignorato per permettere l'utilizzo dell'applicazione ad un solo utente alla volta, altrimenti si creerebbero situazioni in cui entrambi gli utenti potrebbero andare a settare uno stesso pin e senza rendersene conto creare instabilità nel sistema.

Per il resto hai perfettamente ragione, avevo intenzione di valutare l'utilizzo di una cifratura Base64 o 128 e l'utilizzo dei cookie per la gestione della sessione, ma ancora non mi metto al lavoro; se hai qualche consiglio in merito è davvero molto gradito :wink:

I pin 2-3-4-5-6 cambiano di stato ma non viene reso visibile in quanto (come puoi notare dal codice) sono "pin il cui stato dipende da un ingresso"

Questo non l'hai detto nelle specifiche però devi ammetterlo, tali condizioni dei pin OUT dipendenti dagli analog non sono visualizzati sulla web page, sono identici a tutti gli altri, non c'è nulla che faccia pensare ad una dipendenza tipo (input > di x) o (input < di x) o (input == a x) .. riporta i valori analog a fianco al pin che possiede il vincolo evidenziando un enable/disable alla commutazione manuale.

La password può essere cambiata solo da un utente che ha già effettuato il Login e quindi ad un utente a cui è consentito farlo.

Si, questo l'ho capito, ma una altra persona può sedersi alla tua scrivania mentre sei a fare pipì, per questo la prassi chiede sempre di verificare la vecchia passw, essa la conosce solo il proprietario assoluto.

Consigli per rendere la chiave non visibile?

beh, te l'ho detto, ormai tutti i browser aprono un popup di autenticazione quando lanci un 401 al posto del 200 OK, se proprio vuoi spedire in chiaro le chiavi non criptate, usa il json, jsonp, ajax, delega il compito al client di caricare le lib javascript per non appesantire lo sketch, inoltre tale metodo ti consente un pollig client-server persistente (la pagina si aggiorna senza essere ricaricata ogni volta), ciò allegerisce la ethernet che deve solo inviare i dati e non la pagina intera.

Puoi optare all'uso di una SD che contiene il file di installazione html che resterà sul client per sempre una volta fatto il download di essa (un po' come funziona la telecamera IP, si scarica il viewer che è contenuto nel chip di essa una volta solo, poi le connessioni successive lavorano con solo scambio di pochi byte.

Puoi riconoscere se chi si collega è un SO tipo linux, un windows, un apple, un android ...
Puoi leggere anche il modello dello smartphone che possiede chi si connette (se non lo ha nascosto)
Puoi riconoscere la lingua usata dal client che si collega
Puoi riconoscere il tipo di browser che fa la connessione Win explorer, firefox, crome, Thunderbird .. ecc
Puoi sapere l'IP remoto e il suo MAC di chi si collega e porre delle restrizioni ...
Fare tutto è un po' stretto per una Uno, però si possono fare.

Le mie non sono critiche sul tuo lavoro, sono osservazioni basate su centinaia di ore di studio, prove e perchè no anche incaxxature, anzi ... quello di generare una chiave casuale da spedire al client ha attirato la mia attenzione, anche il digest autentication usa un metodo opzionale simile usando ad esempio data/ore/min/sec creando key univoche.
Hai fatto un lavorone, ti ho risposto per farti notare dove può essere migliorato, se non avessi notato impegno e lavoro da parte tua, non ti avrei nemmeno risposto :slight_smile:

ciao

Ti ringrazio per il tempo speso e per i consigli, appena recupero un pò di tempo riprendo il lavoro attuando queste migliorie :wink:

pablos:
Puoi riconoscere se chi si collega è un SO tipo linux, un windows, un apple, un android ...
Puoi leggere anche il modello dello smartphone che possiede chi si connette (se non lo ha nascosto)
Puoi riconoscere la lingua usata dal client che si collega
Puoi riconoscere il tipo di browser che fa la connessione Win explorer, firefox, crome, Thunderbird .. ecc
Puoi sapere l'IP remoto e il suo MAC di chi si collega e porre delle restrizioni ...
Fare tutto è un po' stretto per una Uno, però si possono fare.

Il riconoscimento del SO si basa sulle informazioni fornite dal browser, specialmente l'User Agent, roba che su alcuni browser,ad esempio QtWeb, si cambia facilmente.
Il MAC è banale da cambiare. Su Win sta in una chiave di registro, basta cambiarla.
L'IP meno ma se aspetto che ti scolleghi mi posso collegare con il tuo IP. Ma una protezione basata su IP serve solo sulla LAN a meno che tu accedi da dispositivi con IP pubblico fisso.
Purtroppo mi sa che un metodo di autenticazione robusto sia fuori portata di un Arduino. Spero di sbagliarmi e di avere smentite. Forse uno XOR con una chiave lunga 40 caratteri?
Se dovessi accedere da fuori la LAN mi limiterei forse ad inserire la sicurezza nel router, ad esempio aprendo una porta con il port knocking cosa però fattibile se puoi usare openWRT o firmware simili. Ciò però complicherebbe un pochino l'accesso. Mai provato.

Il riconoscimento del SO si basa sulle informazioni fornite dal browser, specialmente l'User Agent, roba che su alcuni browser,ad esempio QtWeb, si cambia facilmente.

Il riconoscimento dell' SO è solo svantaggioso per chi lo cambia o nasconde. Se ti colleghi al mio web server con uno smartphone ti invio pagine formattate per il tuo telefono ottenendo una visualizzazione corretta con jsmobile, altrimenti se sei un win o altri, ti invio altre pagine, quindi cambiarlo è inutile e controproducente.

Conoscere IP remoto e MAC Della macchina remota per creare delle connessioni riservate ai pochi... Queste info non transitano dall'header http.... le letture le puoi fare solo dialogando con i registri del 5100 / 5200... Vedere su quale socket è entrato e chiudere gli altri o tutti... Ho parlato di riconoscere vari parametri più o meno utili se poi li vuoi smontare tutti

Scusa cosa vuol dire "aspetto che ti scolleghi e mi collego col tuo IP" forse volevi dire... "mi collego al tuo IP"
La nuova connessione sostituisce la precedente quindi non è necessario attendere, allora tanto vale che blocchi il sok 1-2-3 e lasci a perto solo lo 0.

io uso pass generate dal browser in MD5
una di queste è 0dd65ff10901d649a98b26d16604dd0e me la vuoi decriptare? :slight_smile:

Pablos,
le identificazioni di SO, MAC e IP sono facilmente intercettabili e falsificabili. Basta un programma di ascolto e cattura pacchetti tipo kismet e tu riesci anche a capire la tipologia di rete e quali client sono associati agli Access Point.

Piuttosto la pass MD5 riesci ad utilizzarla con Arduino? Se si pensi che il codice si potrebbe aggiungere allo sketch di antonyflour?

Nel frattempo ho inserito una autenticazione banale di tipo Base64 e inserito un po' di Javascript per alleggerire le informazioni inviate dal server al client.
Se avete un po' di tempo date un'occhiata, testate lo sketch, trovate bug, condividete i vostri consigli ecc. ;D

La libreria usata per la codifica Base64 è recuperabile al link: GitHub - adamvr/arduino-base64: A base64 library for the arduino platform, written in C

Vi allego lo sketch

controller_remoto.ino (15.4 KB)