[Debutant] Arduino Dino & sécurité

Bonjour à tous,

Je découvre le monde merveilleux de l'Arduino à travers un petit projet perso, et j'ai besoin de vos conseils pour aller plus loin :
Je souhaite pouvoir commander facilement via mon iphone ma porte de garage à l'aide du arduino DIno (carte à 4 relais).

Grace au forum après avoir fais quelques tests avec succès de commande à travers UDP, serveur web & touchOSC j'ai choisis les pistes suivantes :

Programme :

  • commander l'arduino via touchosc
  • commander l'arduino via une application Wifigarage sur l'appstore aprés avoir modifié le code coté arduino pour l 'utiliser en ethernet simple

Réseau :

  • utiliser le wifi local uniquement (ajout d'un AP que je pourrais capter de ma voiture)
  • utiliser le 3g (via une redirection de port de ma box)
  • utiliser les 2 wifi et 3G

-utiliser le protocole osc vous semble t il suffisamment sécurisé pour être utilisé avec l'extérieur ? car à part le nom qu'on donne au bouton de contrôle(au lieux de l'appeler button1 ou pourrais lui donner un nom sur 10 caractères) je ne vois pas comment on peut implémenter de la sécurité. On pourrait peut être trapper l'adresse MAC du demandeur au niveau du Arduino ?

Si vous avez un avis sur la question il est le bien venu !

D'avance merci.

Pourquoi aller chercher des applis spécifiques sur iPhone ?
Pourquoi pas une simple page Web ?

Tu parles de Wifi donc je suppose que tu considères aussi un shield Ethernet ou Wifi sur ton Arduino ?
Tu peux donc faire un micro-site à 1 page web sur ton Arduino avec un gros bouton Ouvrir et un gros boutton Fermer !

Pas besoin de protocole OSC ou autre.

Pour la sécurité, déjà si ton Wifi est verrouillé, seul ceux qui ont accès au Wifi pourront avoir accès à la page Web.
C'est déjà pas mal.

Tu peux aussi implémenter une sécurité supplémentaire un choisissant un une URL complexe genre http://x.y.z.t/un-code-long-que-tu-choisit-et-que-personne-ne-peut-inventer
Et tu fait en sorte que l'Arduino ne réponde pas à http://x.y.z.t/

Merci Barbudor pour la reponse rapide !

Oui en fait la DIno est une carte "low cost" avec ethernet intégré.

Pour le microsite je pense effectivement en faire un en "secours" en cas de pbs, j'en ai fait en proto ca marche plutôt bien.
Mais je ne veux pas avoir besoin de signer avec un login et mdp a chaque fois que je veux ouvrir ma porte.

Pour le wifi effectivement si j'utilise uniquement en solution "locale" pas besoin de sécurité autre que le wpa.
Mais je voudrais surtout pouvoir l'utiliser en passant par internet, et là juste planquer la page au fin fond d'une url .... ca me semble pas top.

C'est pour ca que je voulais éventuellement détourner l'interface de wifigarage puisque qu'elle intègre des variables pour la securité et que le code coté arduino est libre.

Bonjour,

Sécurité et protocole OSC n'ont jamais fait bon ménage.
Le protocole OSC n'ayant jamais prévu la moindre sécurité c'est comme vouloir mettre une rustine sur un pneu éventré.

Si tu veut concevoir un systéme sécurisé le mieux et de concevoir une application utilisant un protocole fait maison.

Protocole dans lequel tu intégreras une méthode connexion :
(quelques exemples classiques)

  • classique identifiant / mot de passe
  • clef à usage unique ("one time token") + algo de génération maison
  • clef "maitre" en dure dans ton programme

Ainsi que divers méthode "anti replay", anti injections, etc ... :

  • code tournant ("rolling code")
  • checksum CRC (en utilisant un polynôme de calcul non standard)
  • cryptage (RC4 ça passe sans probléme même sur une carte arduino)
  • systéme de "handshake" (poignée de mains) et de session, pour éviter que plusieurs personnes utilise le même identifiant simultanément (ou qu'une personne mal intentionné récupère au vol une session déja ouverte).

malphodo:
Pour le microsite je pense effectivement en faire un en "secours" en cas de pbs, j'en ai fait en proto ca marche plutôt bien.
Mais je ne veux pas avoir besoin de signer avec un login et mdp a chaque fois que je veux ouvrir ma porte.

Pour le wifi effectivement si j'utilise uniquement en solution "locale" pas besoin de sécurité autre que le wpa.
Mais je voudrais surtout pouvoir l'utiliser en passant par internet, et là juste planquer la page au fin fond d'une url .... ca me semble pas top.

Si ton application est disponible en dehors de ton intranet il faudra prévoir :

  • anti bruteforce (pour éviter qu'une personne test tout les combinaisons de login possible)
  • anti robots / scanner (pour éviter qu'un robots ne vienne foutre la merde en détectant un port ouvert)

A mon avis vouloir utiliser une carte arduino telle quelle en ethernet pour une application "critique" c'est ce tirer une balle dans le pied.
Pour un systéme domotique en intranet ça passe (tu est chez toi il y a peu de risque que quelqu'un viennent foutre la m*rde ... enfin c'est vite dit).
Pour un systéme connecté au web il serait préférable d'utiliser un mini serveur web (routeur reconditionné, etc ...) afin de mettre en place un systéme solide.

La sécurité informatique ne consiste pas à cacher les choses derrière une URL introuvable (= méthode de la "boite noir").
Du reste même une URL bien caché ne résiste pas longtemps à un pentester utilisant les bons outils.

Merci Skywood pour ta réponse plus que complète !

Donc c'est décide je laisse tomber l'OSC pour l'utilisation en WAN.
Par contre l'idée d'utiliser le client Wifigarage est intéressant puisque qu'il intègre login/mdp + clé maitre.

Donc coté client : login/mdp + clé maitre.
Coté Arduino : login/mdp + clé maitre + anti brute force + filtrage MAC

Si j'arrive à faire tout çà je serai déjà bien content pour une première application :slight_smile:
D'autant plus que je ne trouve rien comme exemple de "trappage" des mac accédant au serveur web.

Dans un second temps je verrais pour implémenter éventuellement une "vraie" sécurité en plaçant l'Arduino sur un VLAN spécifique qui passera par un firewall + certificat

malphodo:
Par contre l'idée d'utiliser le client Wifigarage est intéressant puisque qu'il intègre login/mdp + clé maitre.

Connais pas ce logiciel, à voir.

malphodo:
Donc coté client : login/mdp + clé maitre.
Coté Arduino : login/mdp + clé maitre + anti brute force + filtrage MAC

Si tu utilise un login/mdp tu n'est pas obligé d'avoir une clef maitre, c'est quand tu n'as rien d'autre que c'est intéréssant.

malphodo:
Si j'arrive à faire tout çà je serai déjà bien content pour une première application :slight_smile:
D'autant plus que je ne trouve rien comme exemple de "trappage" des mac accédant au serveur web.

Pour le bruteforce il suffit de faire un compteur de temps et un compteur de tentative.
Si il y trop de tentative en x temps tu ban.

Pour le ban justement c'est avec ton firewall qu'il faudrait discuter.
Perso j'utiliserai iptable pour capturer la réponse "BANNED" de l'arduino et ajouter la mac / ip au régles de ban.
ça éviterai cote arduino à stocker une liste d'ip/mac et iptables est bien plus puissant qu'un truc fait main.
Regarde les exemples pour bannir les "w00tw00t" c'est le même principe mais en sortant (arduino -> internet).

En fait le firewall c'etait plutot dans un deuxieme temps .... ma baie de serveur étant en cours de modification.
Iptable ca tourne sur Linux çà ...? je regarderait mais j'ai rien pour le moment qui tourne en linux.

Et si je prend le sujet dans l'autre sens :
J'autorise une liste de MAC dans l'arduino + antibrute force 3 niveaux (exemple pas plus de 3 tests en 10 minutes + 2 série d'échec désactivation du compte + 2 séries d'échecs sur 2 comptes = désactivation complet du service)

Dans un deuxième temps je pourrais remplacer la fonction de "désactivation complet du service" par un ban via le FireWall.

Par contre j'ai encore passé du temps ce matin je trouve rien sur le filtrage mac via arduino ... :frowning: je vais regarder du coté code pour serveur dhcp

Bon je commence doucement en utilisant la librairie ethershield et en modifiant quelques exemples.
Ci dessous le code sur lequel je commence à bosser.

Mais je bloque j'ai un peu de mal à comprendre le principe des duffers…
Dans mon loop dans ma condition if (buf[IP_PROTO_P]==IP_PROTO_UDP_V j'aimerai retourner la totalité de mon paquet UDP reçus sous forme de string pour le travailler, pour en faire un serial.print par exemple.
Si vous aviez une piste :slight_smile:

#include "EtherShield.h";
#include "Configuration.h";


#define BUFFER_SIZE 750
static uint8_t buf[BUFFER_SIZE+1];

char reply[]="00000000";

EtherShield es=EtherShield();

uint16_t plen, dat_p;

///----------------------------------------------------------
void setup(){
  
  Setup_Pins();
  es.ES_enc28j60Init(mymac);
  es.ES_init_ip_arp_udp_tcp(mymac,myip, MYWWWPORT);
  Serial.begin(9600);
  Serial.println("Init OK");

} // end setup
///----------------------------------------------------------
void loop(){
  
    // read packet, handle ping and wait for a tcp packet:
    dat_p=es.ES_packetloop_icmp_tcp(buf,es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf));
     
     
     
    if (buf[IP_PROTO_P]==IP_PROTO_UDP_V){
       Serial.println("data recues");
              
       Relay_Control();
       Status_Reply();
       
       es.ES_make_udp_reply_from_request(buf,reply,8,12345);
       
            
       buf[IP_PROTO_P]=0;
    }    
    
 
    
} // end loop
///----------------------------------------------------------
void Setup_Pins(){
  
  pinMode(5, OUTPUT); digitalWrite(5, 0);
  pinMode(6, OUTPUT); digitalWrite(6, 0);
  pinMode(7, OUTPUT); digitalWrite(7, 0);
  pinMode(8, OUTPUT); digitalWrite(8, 0);
  
} // end Setup_Pins
///----------------------------------------------------------
void Relay_Control(){
                    
  if ((buf[59]=='F')&(buf[60]=='F'))
     {
      if ((buf[61]=='0')&(buf[62]=='1'))  // Relay 01
         {
         if ((buf[63]=='0')&(buf[64]=='1')) digitalWrite(8, 1);
         if ((buf[63]=='0')&(buf[64]=='0')) digitalWrite(8, 0);
         return;
         }
                      
      if ((buf[61]=='0')&(buf[62]=='2'))  // Relay 02
         {
         if ((buf[63]=='0')&(buf[64]=='1')) digitalWrite(7, 1);
         if ((buf[63]=='0')&(buf[64]=='0')) digitalWrite(7, 0);
         return;
         }
                      
      if ((buf[61]=='0')&(buf[62]=='3'))  // Relay 03
         {
         if ((buf[63]=='0')&(buf[64]=='1')) digitalWrite(6, 1);
         if ((buf[63]=='0')&(buf[64]=='0')) digitalWrite(6, 0);
         return;
         }
                         
      if ((buf[61]=='0')&(buf[62]=='4'))  // Relay 04
         {
         if ((buf[63]=='0')&(buf[64]=='1')) digitalWrite(5, 1); 
         if ((buf[63]=='0')&(buf[64]=='0')) digitalWrite(5, 0); 
         return;
         }
                                         
    }                  
} // end Relay_Control
///----------------------------------------------------------
void Status_Reply(){
  
     if(digitalRead(A5)==1) reply[0]=0x31;  // Input 01
       else reply[0]=0x30;
     if(digitalRead(A4)==1) reply[1]=0x31;  // Input 02
       else reply[1]=0x30;
     if(digitalRead(A3)==1) reply[2]=0x31;  // Input 03
       else reply[2]=0x30;
     if(digitalRead(A2)==1) reply[3]=0x31;  // Input 04
       else reply[3]=0x30;
       
     if(digitalRead(8)==1)  reply[4]=0x31;  // Relay 01
       else reply[4]=0x30;
     if(digitalRead(7)==1)  reply[5]=0x31;  // Relay 02
       else reply[5]=0x30;
     if(digitalRead(6)==1)  reply[6]=0x31;  // Relay 03
       else reply[6]=0x30;
     if(digitalRead(5)==1)  reply[7]=0x31;  // Relay 04
       else reply[7]=0x30;  
       
} // end Status_Reply///----------------------------------------------------------

uint8_t mymac[6] = {0xBE,0xBA,0x50,0x2C,0x6F,0x67};
uint8_t myip[4] = {192,168,0,25};
uint16_t MYWWWPORT = 80;

Bon me revoilà ... entre temps j'ai découvert la différence entre serial.print et serial.write :*

Bref avec ce bout de code :

void loop(){
  
    // read packet, handle ping and wait for a tcp packet:
    dat_p=es.ES_packetloop_icmp_tcp(buf,es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf));
    
    if (buf[IP_PROTO_P]==IP_PROTO_UDP_V){ 
      // Serial.println(buf[IP_PROTO_P]);
       if (buf[IP_PROTO_P]==IP_PROTO_UDP_V){
      
      udp_length=buf[39]-8; // calculate UDP data lenght
           
      for (int i = 0; i < udp_length; i++)
       {
         Serial.write(buf[42+i]);
        }
       Serial.println(); 
       Relay_Control();
       Status_Reply();
       es.ES_make_udp_reply_from_request(buf,reply,8,12345); 
       buf[IP_PROTO_P]=0;
    } }   
} // end loop

je recupère sur mon moniteur serie:

/1/push1°°°°,f°°?°°°
/1/push1/°°°°,f°°°°°°
/1/push1/z°°,f°°°°°°

ou "°" représente un caractère carré que je n'arrive pas à reproduire pour le forum.
Moi ce qui m'intéresse c'est "/1/push1" et "/1/push1/z"

Vous pensez que je dois travailler au niveau chaine de caractère ou affiner le trappage de ma trame UDP ?
D'avance merci

Sans savoir exactement où tu veux en venir, quel est le problème ca va être dur de t'aider.

Où est documenté le protocole de WifiGarage ?
Que t'attends tu a recevoir ?

Je ne connais pas la lib Ethernet mais ca me parait bizarre d'utiliser une fonction de réception TCP pour ensuite traiter un paquet UDP.
Tu es en UDP ou en TCP ?

Effectivement j'avais donné plein de pistes au début et j'ai oublié de preciser la direction XD

En gros mon principale problème est que j'utilise une carte un peu exotique a base d'enc28j60 résultat les exemples intéressant intégrant de l'authentification poussée que je trouve en TCP / UDP sont à retraduire pour les librairies Ethershield ou Ethercard qui marchent avec ma carte.
N'ayant pas encore le niveau j'ai un peu lâché l'affaire et je suis repartit sur un code plus simple laissant l'aspect sécurité au niveau WIFI local.
J'ai donc décidé dans un premier temps d'utiliser TouchOSC + fonctions UDP de la lib ethershield.
J'ai essayé d'utiliser différentes librairies OSC mais celles ci nécessitent aussi de grosses modif car utilisent la librairie Ethernet qui n'est pas compatible avec mon shield.

Voilà voilà :slight_smile:

Bon ci dessous la partie principale de mon code actuel :

J'ai besoin d'aide sur 2 sujets tous bêtes :

  • J'aimerai bien retourner le contenu de myip[4] sur le port serie hors je n'arrive pas a avoir l'adresse en claire malgrés toutes mes tentatives de format et de convertion
  • for (int i = 0; i < udp_length; i++)
    {
    Serial.write(buf[42+i]);
    }
    -> je voudrai passer çà dans une string pour la retravailler ensuite, mais je bloque =(
    J'ai bien essayer un truc du genre :
    char UDPmsg [udp_length];
    et
    for (int i = 0; i < udp_length; i++)
    {
    UDPmsg = UDPmsg + (buf[42+i]);
    }
    mais ca marche pas :frowning:

#include "EtherShield.h"

uint8_t mymac[6] = {0xCF,0x70,0x7C,0xE4,0x8A,0xB8};
uint8_t myip[4] = {192,168,1,25};
uint16_t MYWWWPORT = 80;
int port = 12345;
char garageup[] = "push1";
char garagdown[] = "push2";

#define BUFFER_SIZE 750
static uint8_t buf[BUFFER_SIZE+1];

char reply[]="00000000";

EtherShield es=EtherShield();

uint16_t plen, dat_p;
static uint8_t udp_length;
static uint8_t udp_buffer[50];

///----------------------------------------------------------
void setup(){

Serial.begin(9600);
Setup_Pins();
es.ES_enc28j60Init(mymac);
es.ES_init_ip_arp_udp_tcp(mymac,myip, MYWWWPORT);
Serial.println("Start");
Serial.print("Port :");
Serial.println(port);

} // end setup
///----------------------------------------------------------
void loop(){

// read packet, handle ping and wait for a tcp packet:
dat_p=es.ES_packetloop_icmp_tcp(buf,es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf));

if (buf[IP_PROTO_P]==IP_PROTO_UDP_V){
// Serial.println(buf[IP_PROTO_P]);
if (buf[IP_PROTO_P]==IP_PROTO_UDP_V){

udp_length=buf[39]-8; // calculate UDP data lenght
// udp_length=buf[39]-20; // calculate UDP data lenght
//affichage du message UDP

for (int i = 0; i < udp_length; i++)
{
Serial.write(buf[42+i]);
}
Serial.println();
//Relay_Control();
//Status_Reply();
//es.ES_make_udp_reply_from_request(buf,reply,8,port);
buf[IP_PROTO_P]=0;
} }
} // end loop

Je me répond à moi méme :slight_smile: :
çà :

String UDPMsg;
char c;

et

for (int i = 0; i < udp_length; i++)
{
//Serial.write(buf[42+i]);
c = buf[42+i];
UDPMsg += c;
}
Serial.println(UDPMsg);

Marche bien pour passer le contenu de mon message udp dans une string.

Reste la partie adresse ip, pas vraiment nécessaire mais pour le fun et progresser XD

J'ai bien essayé la emme technique :

for (int i = 0; i < myip[4]; i++) //boucle concatenation message
{
//Serial.write(buf[42+i]);
c = myip[4+i];
IPAdresse += c;
}

mais ca retourne pas ce que je veux :frowning:

D'autre par j'essaye de renvoyer un message UDP contenant /1/label1 "ok" avec les fonctions d'ethershield, hors je n'arrive à faire passer le " dans le char*

char* UDPRep;

et

UDPRep = "/1/label1 ok";

Serial.println(UDPRep);
es.ES_make_udp_reply_from_request(buf,UDPRep,12,port);

çà ca marche mais le message est pas interprété car lje dois mettre le ok entre "" et c'est là que ca devient compliqué :slight_smile: