Web server / Home Security

Eventually I would like this code to work as a home security system, where I can see the output of several zones and arm/disarm the alarm as well from the webpage.

Right now I am working on the password portion of accessing the webpage, but I can't figure out how to get the input from an HTML form into a variable which I can check in the code. I "borrowed" a section of code that checks the input from the Serial monitor, but I can't figure out how to switch that to the HTML form. I am using POST.

Feel free to change anything in the code below... I am a noob when it comes to comes to coding and Arduino.

Thanks in advance for any help!!

/*
  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 4 Sep 2010
 by Tom Igoe
 modified again 27 May 2011
 by Chris Baer
 
 */

#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 };
byte ip[] = { xxx,xx,xx,xx };
byte smtp[] = { xx, xx, xx, xx }; // my smtp server ip
int time = 5000;
int wait = 2000;
int x = 0;
int passwordcorrect = 0;
char password;
char sensor;
char input;
Server server(250);
Client client(smtp, 25);
    int ledPin = 10;       // the led is hoooked up to this pin
    int passChar1 = 't';   // the first character of the password
    int passChar2 = 'e';   // the second character of the password
    int passChar3 = 's';   // the third character of the password
    int passChar4 = 't';   // the fourth character of the password
    int nextChar;
    int charCount;


void text(int x)
{
  Serial.println("texting now...");
   delay(3000);
   Serial.println("connecting...");
  delay(3000);
 if (client.connect()) {
                        Serial.println("connected");
  
                        client.println("HELO localhost"); /* say hello (statement after helo is needed but irrelevant)*/
                          delay(wait); /* wait for a response */

                        client.println("MAIL From: Arduino@arduino.com"); /* identify sender, this should be the same as the smtp server you are using */
                          delay(wait); /* wait for a response */

                        client.println("RCPT To: xxx@txt.att.net"); /* identify recipient */
                        delay(wait); /* wait for a response */

                        client.println("DATA");
                          delay(wait); /* wait for a response */
 
                        client.println("to:xxx@txt.att.net"); /* identify recipient */
                        client.println("from: Arduino@arduino.com "); /* identify recipient */
                        client.println("Subject: You Have Mail!!"); /* insert subject */

                        client.println(x); /* insert body */
                        client.println(" is bad");
                        client.println("."); /* end email */
                
                        client.println("QUIT"); /* terminate connection */
                         delay(wait); /* wait for a response */
                       
 
   client.println();
  
 } else {
   Serial.println("connection failed");
 }
  
}
void setup()
{

  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.begin(9600);
 Serial.println("setup...");
       Serial.begin(9600);
      pinMode(ledPin, OUTPUT);
      digitalWrite(ledPin, LOW);
      charCount = 0;
      int passwordcorrect = 0;
}
    void psswd(){
      if (Serial.available()) {
        nextChar = Serial.read();
   
        if (charCount == 0) {
          // check for the first char of the pwd...
          if (nextChar == passChar1) {
            charCount = 1;  // got it, so update the character counter
          } else {
            charCount = 0;  // wrong character, so reset count to zero
          }
        }
        else if (charCount == 1) {
          // check for the second char of the pwd...
          if (nextChar == passChar2) {
            charCount = 2; // got it, so update the character counter
          } else {
            charCount = 0; // wrong character, so reset count to zero
          }
        }
        else if (charCount == 2) {
          // etc.
          if (nextChar == passChar3) {
            charCount = 3;
          } else {
            charCount = 0;
          }
        }
        else if (charCount == 3) {
          if (nextChar == passChar4) {
            charCount = 4;
          } else {
            charCount = 0;
          }
        }
      
        // has complete password been entered yet?
        if (charCount == 4) {
            Serial.println("password accepted");
            // led on
            digitalWrite(ledPin, HIGH);
           passwordcorrect=1;
            charCount = 0;
         }
         else if (charCount == 0) {
           // count was set to zero, meaning a bad char was received.
            Serial.println("Bzzt!  bad password");
            // blink the led
            passwordcorrect = 0;
            delay(10000);
            digitalWrite(ledPin, LOW);
            delay(100);
        }
      }
    }

void loop(){
webpage(passwordcorrect);
Serial.println("Please enter the password.");
psswd();
Serial.println(password);
}
void webpage(int passwordcorrect)
{
  // listen for incoming clients
  Client client = server.available();
  if (client) {
    // an http request ends with a blank line
    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) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println(); // don't remove this line or for some reason it won't work
          client.println("<BODY BGCOLOR=#E3E4FA TEXT=#000065>");
          client.println("<h1><div align='center'><font color='#000065'><B>Arduino Alarm Status v1.0:</B></font color></div></h1>");
          client.println("<TITLE>Arduino Alarm Status</TITLE>");
          client.println("<form name=\"input\" action=\"password\" method=\"post\"> Password: <input type=\"password\" name=\"password\"> <input type=\"submit\" value=\"Submit\"> </form>");
          client.println(password);
          Serial.println(password);
          client.println("password correct?");
          client.println(passwordcorrect);
         client.println("
");
         client.println("
");
               
        
          if  ( passwordcorrect == 1 )
          // output the value of each analog input pin
          for (int analogChannel = 0; analogChannel < 3; analogChannel++) {
            if (analogRead(analogChannel) > 500)
            {
            client.print("<font color='#000065'>analog input ");
            client.print(analogChannel);
            client.print(" is ");
            client.print(analogRead(analogChannel));
            client.println("<BODY TEXT=#347C2C>");
            client.println("<font color='#00FF00'>good status");
            client.println("
");

            }
             else
            {
            client.print("<font color='#000065'>analog input ");
            client.print(analogChannel);
            client.print(" is ");
            client.print(analogRead(analogChannel));
            client.println("<BODY TEXT=#347C2C>");
            client.println("<font color='#FF0000'> ALARM!!!");
            client.println("
");  
            //text(analogChannel);    // text the channel that is bad 
            }
          }
          break;
        }
     
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }}
    else if ( passwordcorrect == 0 )
    {
      client.print("<font color='#000065'>analog input ");
      client.println("wrong password given");
    }
 
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
  }

This is obviously not a secure way to do it, that would be a really, really big example. However, this will parse an input (a little bit) and gives you something to start with and expand upon. This is ONLY a code fragment so you will have to adapt it to your code. Just steal the idea to get you started. I'm sure you will notice that I started with the same example you did.

   Client ControlClient = Control.available();
   if (ControlClient) {
    // an http request ends with a blank line
    while (ControlClient.connected()) {
      if (ControlClient.available()) {
        char c = ControlClient.read();
        // if you've gotten to the end of the line (received a newline
        // character) you can send a reply
        if (c != '\n' && c!= '\r') {
          netbuf[index++] = c;
          if (index >= sizeof(netbuf)) // max size of buffer
            index = sizeof(netbuf) - 1;
          continue;
        }
        netbuf[index] = 0;
        Serial.println(netbuf);
        // standard http response header
        strcpy_P(general, PSTR("HTTP/1.1 200 OK"));
        ControlClient.println(general);
        strcpy_P(general, PSTR("Content-Type: text/html"));
        ControlClient.println(general);
        ControlClient.println();
        if (strstr_P(netbuf,PSTR("GET / ")) != 0){   // This will put up the time if you have it.
          strcpy_P(general, PSTR("<html><body><h1>"));
          ControlClient.print(general);
          strcpy_P(general, PSTR("My Web Site
"));
          ControlClient.print(general);
          tNow = now();
          strcpy_P(Sgeneral,PSTR("%d:%02d:%02d %d/%d/%d"));
          sprintf(general,Sgeneral,hour(tNow),minute(tNow),second(tNow),month(tNow),day(tNow),year(tNow));
          ControlClient.println(general);
          strcpy_P(general, PSTR("
</h1></body></head></html>"));
          ControlClient.println(general);
          break;
        }
        else if (strstr_P(netbuf,PSTR("GET /supersecretpassword")) != 0){ // obviously not totally secure, but you can check stuff this way
          tNow = now();
          strcpy_P(general,PSTR("Wow, you guessed it !"));
          ControlClient.println(general);
          break;
        }
        else{
          strcpy_P(general,PSTR("You messed it up dummy"));
          ControlClient.println(general);
          break;
        }
      }
    }
   }
   ControlClient.stop();

Nice project! I'm currently into something very similar. Look at "Iphone control program over network: someone interested?" for more info on that. When my code is ready i'll post it in that topic.

What you should do to ensure security:

put a define statement in front of you program with a preferable very long password like (#define PASS 765456787654 )
Then have a statement in your server loop poll for that data before you output html. My Iphone app for example is bound to give that data before any data transmission is done, then when the first password is correct a timeout starts in which the iPhone has to give a second password.

To make sure you are safe from bruteforcing implement an ipblacklist. To do so look at this post http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1272506295/all , at the last post.

There you will find a very usefull ethernet extension which is capable of getting the client's IPv4 adress.
Now all you have to do is check for false password entries and for example the second time the password is incorrect you put that ipadress into the blacklist and have an ip check in front of the html output.

Note: This could theoretically lead you vulnerable to DOS attacks, but i havent checked this for myself.

I hope this was anyhow useful,
btz

If the connection is not secure the password would be sniffed over LAN (google to 'arp poisoning')

Guglio:
If the connection is not secure the password would be sniffed over LAN (google to 'arp poisoning')

Good point.
How can we secure the connection between arduino -> page -> mobile application ?

It all depends on how secure you want to be. If you want true security, you'll have to encrypt; good luck with that on an arduino. Not many people have a clue what a sniffer is and very few of them are where you're going to by typing it in. So, consider how much risk you're willing to accept.

Unless you're a bank or credit card company, breaking into your home automation is not very attractive. Don't put your address on the screen !

Even simple schemes to modestly "scramble" things that might be sniffed in transit MAY be enough to convince Bad People to go find something else to hack.

Part of the trick will be to find a way to VARY what is sent as the password, so that the sniffer can merely send the scrambled password, not ever knowing the password itself.

A challenge-response system may be an answer.

To avoid complex encryption and provide reasonable security against sniffers, that is acceptable on an Arduino, I'd recommend you to consider
One Time Passwords (OTP) The trick is that you have a "shared secret" (the key) at both sides, but what you send is not the key but the result of
some "hash" operations on the key and some variable input. This makes it useless to sniff.

For example, you could use the MD5 algorithm (see MD5 - Wikipedia) and send MD5 (key + millis + nonce), along with the millis value (coming from arduino), while the "nonce" is some
random data generated by the other side. That way, none of the party can cheat. To avoid padding, you should find some way to reach 512 bits (32 integers). Running multiple times the MD5 algorithm can increase the security a bit. To avoid modification of the message by a "man-in-the-middle", you should also incorporate the content of the message in the hash input.