[3/4 Résolu] Mega 2560 + shield Ethernet serveur accessible sans mot de passe

Bonjour,

Débutant, je viens de faire un exercice de Web serveur sans carte SD.
Pour ce faire, j’ai utilisé et adapté des tutos trouvés sur le net.
Pour me connecter, je fournis l’adresse IP de ma box qui redirige vers Arduino.
Pour effectuer une commande (LED), je dois d’abord fournir un mot de passe.
Lorsque je suis seul, tout va bien.

Le problème est que si un autre internaute se connecte également durant ma
connexion, il a accès à mes commandes sans avoir entré le mot de passe.
J’ai cru lire quelque part que la connexion Ethernet pouvait supporter 3 ou 4
clients simultanés ?
Il semblerait que toutes les variables soient communes à tous les “connectés” ?
Il n’y a pas d’ouverture de session propre à chaque “connecté” ?

Est-ce normal ?
Pouvez-vous m’indiquer une piste, un lien voire un exemple pour traiter ce problème?
Je ne vois vraiment pas par où prendre le problème.

#include <SPI.h> Je n’utilise que ces 3 bibliothèques
#include <Ethernet.h>
#include <String.h>

Je peux fournir plus de détails, y compris le code complet mais pour l’instant je ne veux
pas encombrer le forum.
Bien à vous
Géryko

Ce serait mieux si tu mettais le code, même si ça "encombre" le forum. ;)

Bonjour,

Voilà le fichier “WebServer_gery_5.ino” mis en Pièce jointe
Mis à disposition de ceux qui voudraient s’amuser et tester. (programme de démo fonctionnel)

(J’espère réussir mon envoi car je ne sais pas lire l’anglais. Menu en français SVP ?)
Dans “Preview” je ne vois pas le fichier joint ??? je clique “Post”
Cordialement
Géryko

WebServer_gery_5.ino (15.1 KB)

Tu trouveras ci dessous un exemple de code avec accès “semi-sécurisé” mais qui ne prend en charge qu’une seule connection.
Si un autre utilkisateur ouvre l’adresse IP il tombera sur la page “echec de chargement de la page” tant que l’utilisateur en cour ne ce sera pas déconnecté.
ça me pose d’ailleurs un problème car si je quitte le navigateur sans me “déconnecté” proprement par l’intermédiaire du navigateur quand je reviens dessus je tombe sur cette erreur.
le seul moyen de ravoir la main c’est de faire un reset de la carte.

En espérant que ça puisse t’aider…

Les fichiers htm sont à placer dans un répertoire www sur la SD.

Si tu les utilises pas ça marche quand meme c’est juste que l’interface sera plus moche :grin:

webserver_https5.zip (4.42 KB)

Bonjour John_lenfr,

Effectivement, ta solution fonctionne suivant tes indications. J'ai testé rapidement et j'ai encore à apprendre des choses qui m'intéressent sur ton fichier. J'ai une formation électronique mais, retraité depuis 2000 j'ai dépassé les 70 balais. Il me faut un peu de temps pour étudier, y compris les fichiers de ton site que je trouve super. Je débute en Arduino, et je programme un peu (bricolages et Elektor) A priori j'ai pu voir que c'était SS_ETHERNET (haut/bas) qui gérait l'accès Ethernet. ' Si un jour, j'ai une autre solution plus "normale" je te tiendrai au courant. Merci pour ton aide et ta gentillesse.

J'attends encore un peu avant de le marquer "résolu" (si j'y arrive !)

Géryko

Ok, pas de quoi.

Le SS_ETHERNET est là pour activer ou non la partie Ethernet du shield et éviter les conflits avec la partie CARTE SD du même shield qui a également sont "PIN" de commande (le SS_SDCARD).

Comme tu le verras mon code est commenté mais en anglais, donc tu pourras utiliser google translate :)

Il y a, c'est sur, d'autres méthodes pour un accès sécurisé sur l'arduino, mais plus compliquées à mettre en oeuvre. Il suffit de faire une recherche sur le forum et tu trouveras d'autres posts parlant du sujet.

Par ailleurs les cartes intégrant une meilleure prise en charge de la partie ethernet doivent peut-être avoir plus d'options?: voir du coté de la Raspberry Pi et de l'Arduino Yun?

En attendant c'est ce que j'ai trouvé de mieux pour l'instant.

;)

Bonjour John_lenfr,
J’ai testé un peu plus ta maquette et je pense avoir trouvé une amélioration.

  1. Pour éviter le reset, considérant la problème assimilable à un plantage, j’ai imaginé
    qu’un Watch Dog pouvait résoudre le problème. 3 possibilités :
    a) en utilisant une tempo réarmable
    b) en utilisant une horloge RTC
    c) matériel/logiciel, avec une capa que l’on charge et en surveillant la décharge.
    C’est cette dernière option que j’ai choisie.
    Voir le fichier joint “webserver_https55.zip” ( ton fichier renommé)

  2. Contrairement à ce que tu disais, il est possible de se reconnecter si on quitte sans se déconnecter.
    Un reset n’est donc pas nécessaire.
    Il suffit de taper dans la barre d’adresse par exemple :
    http://192.168.xx . yyy/menu5” ou “http://192.168.xx . yyy/analog”
    Et au delà, 2 clients simultanés peuvent donc être connectés ! ho ! ho !
    Le 1er qui déconnecte, déconnecte aussi le 2ème.

Bien à toi
Géryko

webserver_https55.zip (22.6 KB)

Bonjour,

Je pense que le plus simple est d’utiliser ce que le protocle HTTP a mis à notre dispostion: l’entête “WWW-Authenticate”.

Il suffit de renvoyer dans l’entête de la page un ligne comme

WWW-Authenticate: Basic realm=\"something\"

pour indiquer au navigateur web qu’il faut demander un mot de passe à l’utilisateur.

Le navigateur web renvoie dans ce cas la saisie de l’utilisateur dans l’entête de sa requête.
Après il ne reste qu’à analyser ledit entête et repérer la ligne qui va bien:

Authorization: Basic dGVzdDp0ZXN0

Si la ligne est absente ou différente, renvoyer le code 401 dans la page web. Sinon renvoyer la page désirée.

Bien sûr le code ici dépend de l’utilisateur/mot de passe saisi. Dans notre exemple il faut saisir ‘test’ pour l’utilisateur et ‘test’ pour le mot de passe.

Avec cette méthode, le navigateur web gère la saise du mot de passe et peut le mémoriser si l’utilisateur le demande, et le mot de passe ne circule pas trop en clair sur le réseau. Cerise sur le gateau, presque rien à ajouter côté code Arduino !

Code complet, adapté de l’exemple WebServer de l’IDE Arduino:

/*
  Web Server
 
 A simple web server that shows the value of the analog input pins.
 using an Arduino Wiznet Ethernet shield. 
 
 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 * Analog inputs attached to pins A0 through A5 (optional)
 
 created 18 Dec 2009
 by David A. Mellis
 modified 9 Apr 2012
 by Tom Igoe
 modified 20 july 2014
 by C. Brandt
 */

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,1,2);

// Initialize the Ethernet server library
// with the IP address and port you want to use 
// (port 80 is default for HTTP):
EthernetServer server(80);

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }


  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}


void loop() {
  //---- quelques variables locales
  char		headerLine[80];
  char		headerIndex;
  bool		passwordOk;


  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {

    Serial.println("new client");
    // an http request ends with a blank line

    //---- initialisation variables
    passwordOk = false;
    headerIndex = 0;

    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {

          if (passwordOk)
          {
            //---- envoi page web normale ----
            client.println("HTTP/1.1 200 OK");
            client.println ("WWW-Authenticate: Basic realm=\"something\"");
            client.println("Content-Type: text/html");
            client.println("Connection: close");
			client.println("Refresh: 5");  // refresh the page automatically every 5 sec
            client.println();
            client.println("<!DOCTYPE HTML>");
            client.println("<html>");
            // output the value of each analog input pin
            for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
              int sensorReading = analogRead(analogChannel);
              client.print("analog input ");
              client.print(analogChannel);
              client.print(" is ");
              client.print(sensorReading);
              client.println("
");       
            }
            client.println("</html>");
          }
          else
          {
            //---- envoi code d'erreur 401 ----
            client.println("HTTP/1.1 401 OK");
            client.println ("WWW-Authenticate: Basic realm=\"something\"");
            client.println("Content-Type: text/html");
            client.println("Connection: close");
            client.println();
            client.println("<!DOCTYPE HTML>");
            client.println("<html>");
            client.println("mot de passe incorrect");
            client.println("</html>");
          }
          break;
        }
        if (c == '\n') {

          //---- test ligne d'entete avec mot de passe
          headerLine[headerIndex] = 0;
          headerIndex = 0;
          Serial.println (headerLine);
          if (strcmp (headerLine, "Authorization: Basic dGVzdDp0ZXN0") == 0)
            passwordOk = true;

          // you're starting a new line
          currentLineIsBlank = true;
        } 
        else if (c != '\r') {

          //---- mémorisation ligne d'entete courante
          if (headerIndex < 79)
            headerLine[headerIndex++] = c;

          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
    Serial.println("client disonnected");
  }
}

Les deux solutions sont intéressantes. Je regarderais ça de plus près.

Je me disais bien qu'il y avait quelque chose de mieux :grin:

Bonjour cbrandt,

Je viens de tester rapidement ta solution "WWW-Authenticate" . Magique, ça semble parfait. Je ferai d'autres tests et il faut que j'adapte mon code pour le mettre en oeuvre. Je ne suis pas rapide. [u]Petit problème[/u] : ne fontionne pas avec IE8/XP (mot de passe incorrect) Il n'y a que des sites en anglais qui parlent d' IE. Je ne comprends pas les explications.

Bonjour John_lenfr, Pour coder/décoder base64 j'ai trouvé : http://webnet77.com/cgi-bin/helpers/base-64.pl

Cordialement Géryko

Bonjour,

Regarde dans le moniteur série arduino: les lignes de l'entête doivent y apparaître, et cheche celle qui ressemble à

Authorization: Basic.....

tu verras comment IE envoie cette ligne, peut-être les majuscules ou autre différence....

D'ailleurs, si tu veux autre chose que test / test, c'est là que tu verras la valeur calculée par le navigateur et tu pourras adapter le code arduino en conséquence.

Bonjour, J'ai essayé le code hier mais sans succès. Je l'ai mis dans ma carte Mega 1280 mais je n'arrive pas à me connecter dessus.

Dans le "serial monitor" l'adresse IP change à chaque reset de la carte et quand je met l'adresse IP indiquée dans mon navigateur (chrome) il me met une erreur comme quoi il ne trouve pas l'adresse indiquée.

J'ai pourtant changé l'adresse MAC et IP dans le programme. Il y a d'autres choses à changer? Une idée?

Bonjour cbrandt,
ça ne fonctionnait pas avec IE8 mais maintenant c’est OK.
Une petite fenêtre m’a signalé un problème de compatibilité d’affichage sur IE8
avec des versions de sites anciens et proposé d’accepter la compatibilité.
Le problème semble disparu mais je ne sais pas l’expliquer ni le reproduire. dommage.
A suivre ! ! !

Pour info :

  • J’ai bien vu. C’est ce que j’avais fait. La ligne “Authorization: Basic…” n’était pas présente.
  • Je n’avais même pas eu à saisir login et PW et ça me renvoyait mot de passe incorrect.
  • Je sais modifier le login/passw.
    Merci

Bonjour John_lenfr,
Tu dis “J’ai essayé le code hier mais sans succès.”
De quel code parles-tu ? Celui de cbrandt ou le mien ??
Sur celui que je t’ai remis, il n’y a que “Serial.begin(9600);” que j’ai oublié de remettre à Serial.begin(115200)
(je m’en suis rendu compte après. Voir nouvelle version sur le forum que j’ai modifié le jour suivant)
Tu n’as pas dû la prendre car le compteur est toujours à 1 (mon test)
A part celà je ne vois vraiment rien. Je n’ai rien changé.
Attention, as-tu mis le montage proposé avec un condensateur ?
( Si A0 < 3V demande de login permanente je suppose ?)
Me tenir informé stp. Il faut trouver l’explication et tu peux compter sur moi.
Je m’en excuse.

Cordialement
Géryko

J'ai voulu tester le code de cbrandt ;) Je ne sais pas pourquoi il ne fonctionne pas. Normalement tu rentres l'adresse IP et le navigateur sort un popup de connexion non? Mais là rien... Je reteste ce soir

john_lenfr: J'ai voulu tester le code de cbrandt ;) Je ne sais pas pourquoi il ne fonctionne pas. Normalement tu rentres l'adresse IP et le navigateur sort un popup de connexion non? Mais là rien... Je reteste ce soir

Tu as mis le code tel quel, en ne changeant que l'adresse ip ? Ce n'est pas normal que le serial monitor indique une adresse différente à chaque reset :astonished: Et l'ip qu'il indique change de quelle façon ?

Edit: Il me vient à l'esprit que l'initialisation du bus spi dans l'exemple webserver qui m'a servi de base n'est pas très correcte... Ajoute ceci au début du setup:

pinMode (53, OUTPUT);
pinMode (10, OUTPUT);
digitalWrite (10, HIGH);
pinMode (4, OUTPUT);
digitalWrite (4, HIGH);
SPI.begin ();

Et retire les périphériques spi autre que le Shields ethernet .

223.171.XXX.XXX

cbrandt: Edit: Il me vient à l'esprit que l'initialisation du bus spi dans l'exemple webserver qui m'a servi de base n'est pas très correcte... Ajoute ceci au début du setup:

pinMode (53, OUTPUT);
pinMode (10, OUTPUT);
digitalWrite (10, HIGH);
pinMode (4, OUTPUT);
digitalWrite (4, HIGH);
SPI.begin ();

Et retire les périphériques spi autre que le Shields ethernet .

Ok avec ces modifications ça fonctionne. Il faut donc gérer les pin Select du shield avec Ethernet OU sd. Je débute avec la carte MEGA, pourquoi faut-il mettre le pin 53 en output?

Par ailleurs, un truc que je n'ai pas trop compris jusqu'à maintenant: si le pin 10 correspond au pin select de l'ethernet et le pin 4 celui de la sd, comment ça se fait que l'ethernet fonctionne meme quand les deux pins sont à l'état haut (c'est à dire en "disable) ?

Dans Chrome quand je n'enregistre pas le mot de passe, la connexion reste quand même active. Si je ferme l'onglet et que je relance, le mot de passe n'est pas demandé. Je dois quitter complètement le navigateur.

Bonsoir cbrandt, Le problème avec IE8/XP recommence après avoir éteint mon PC durant 6h00 mais.... Je viens de passer 4h00 à faire des essais, c'est atroce. La ligne "Authorization: Basic....." n'est pas présente lorsque ça ne fonctionne pas. Toutes les autres lignes semblent correctes. Parfois j'arrive y accéder et après ce cas c'est toujours OK. Je ne sais pas le reproduire. Je ferme IE sans éteindre le PC et je recommence. Parfois c'est OK parfois non. Si j'arrive y accéder, je ne sais pas le reproduire. ça semble aléatoire. La seule chose que je peux affirmer c'est que la ligne "Authorization: Basic....." n'est pas toujours présente.

Nota : j'ai un 2ème PC IE6/XP (sans Arduino raccordé). Mêmes phénomènes aléatoires. à l'allumage : mot de passe incorrect sans avoir eu la boîte dialogue. Je mets en place le moniteur série sur le PC Arduino, je relance IE6 et là c'est OK. J'abandonne pour l'instant. La nuit porte conseil.

Concernant le webserver cbrandt, je n'ai eu aucun problème. OK du 1er coup. (avec mon IP fixe et mac bien sûr)

Effectivement sur 53 PB0 (SS) fonction ressemble à 10 . Bizarre. Géryko

@johnlen_fr:

La pin 53 est le chip select du microcontrôleur Atmega sur les cartes Mega1280 et 2560, alors que sur une carte Uno il s'agit de la Pin 10. Il faut la mettre en output pour indiquer que le mc est maître du bus SPI et en input pour indiquer qu'il est un esclave. Sur la Uno la pin 10 est aussi utilisée pour le chip select du module ethernet.

Mettre une pin chip select à low ne désactive pas un périphérique SPI, ça lui dit juste que se qui se passe sur le bus ne lui est pas destiné. C'est la lib qui passe la pin à low avant de parler à un périphérique et le remet à high après.

Mais je mets toujours tous les chip select en output high avant de faire quoi que ce soit sur le bus SPI pour éviter les conflits.

@geryko:

Désole, pour IE je ne sais pas, je n'utilise que des macs...

Merci cbrant pour la réponse. Il faut que j'assimile tout ça car je n'ai pas encore tout compris :grin:

Le système que j'avais mis en place du type:

#define SS_SD_CARD   4
#define SS_ETHERNET 10

void setup() {
  // Shield Ethernet
  pinMode(SS_SD_CARD, OUTPUT);
  pinMode(SS_ETHERNET, OUTPUT);
  digitalWrite(SS_SD_CARD, HIGH);  // SD Card not active
  digitalWrite(SS_ETHERNET, HIGH); // Ethernet not active
}

void SDCard_stuff() {
  digitalWrite(SS_SD_CARD, LOW);  // SD Card ACTIVE

  //...

  digitalWrite(SS_SD_CARD, HIGH); // SD Card not active
}

void ethernet_stuff() {
  digitalWrite(SS_ETHERNET, LOW);  // Ethernet ACTIVE

 //....

  digitalWrite(SS_ETHERNET, HIGH); // Ethernet not active
}

Est complètement inutile alors?