Common stuff for all my devices' web server pages: css, login, log, ipv4, ipv6, firmware update, clock, reset info etc.

Dependents:   oldheating gps motorhome heating

Security

A password has to be set whenever there has been a software reset. Resets following faults or power on do not require a new password as the hash is restored from the RTC GPREG register.

The password is not saved on the device; instead a 32 bit hash of the password is saved. It would take 2^31 attempts to brute force the password: this could be done in under a month if an attempt were possible every millisecond. To prevent this a 200 ms delay is introduced in the reply to the login form, that gives a more reasonable 13 years to brute force the password.

Once the password is accepted a random session id is created. This is 36 bit to give six base 64 characters but without an extra delay. If an attempt could be made every ms then this would still take over a year to brute force.

The most likely attack would to use a dictionary with, say, 10 million entries against the password which would still take 20 days to do.

Committer:
andrewboyson
Date:
Tue Jun 09 14:33:55 2020 +0000
Revision:
141:1dac268a197d
Parent:
130:9a5b8fe308f1
Added routine to parse a float (double) value from a query.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
andrewboyson 130:9a5b8fe308f1 1 #include <stdbool.h>
andrewboyson 130:9a5b8fe308f1 2 #include <stdio.h>
andrewboyson 130:9a5b8fe308f1 3 #include <string.h>
andrewboyson 130:9a5b8fe308f1 4 #include <stdlib.h>
andrewboyson 130:9a5b8fe308f1 5
andrewboyson 130:9a5b8fe308f1 6 #include "http.h"
andrewboyson 130:9a5b8fe308f1 7 #include "log.h"
andrewboyson 130:9a5b8fe308f1 8
andrewboyson 130:9a5b8fe308f1 9 static char* terminateThisAndGetNextLine(char* p, char* pE) //Terminates this line and returns the start of the next line or NULL if none
andrewboyson 130:9a5b8fe308f1 10 {
andrewboyson 130:9a5b8fe308f1 11 while (true)
andrewboyson 130:9a5b8fe308f1 12 {
andrewboyson 130:9a5b8fe308f1 13 if ( p == pE) { *p = 0; return NULL; } //no more buffer - relies on having designed the buffer to be bigger than an ethernet packet
andrewboyson 130:9a5b8fe308f1 14 if (*p == 0) return NULL; //there are no more lines
andrewboyson 130:9a5b8fe308f1 15 if (*p == '\n') { *p = 0; return p + 1; } //return the start of the next line
andrewboyson 130:9a5b8fe308f1 16 if (*p < ' ') *p = 0; //terminate the line at any invalid characters but keep going to find the start of the next line
andrewboyson 130:9a5b8fe308f1 17 if (*p >= 0x7f) *p = 0; //terminate the line at any invalid characters but keep going to find the start of the next line
andrewboyson 130:9a5b8fe308f1 18 p++;
andrewboyson 130:9a5b8fe308f1 19 }
andrewboyson 130:9a5b8fe308f1 20 }
andrewboyson 130:9a5b8fe308f1 21
andrewboyson 130:9a5b8fe308f1 22 static void splitRequest(char* p, char** ppMethod, char** ppPath, char** ppQuery)
andrewboyson 130:9a5b8fe308f1 23 {
andrewboyson 130:9a5b8fe308f1 24 *ppMethod = NULL;
andrewboyson 130:9a5b8fe308f1 25 *ppPath = NULL;
andrewboyson 130:9a5b8fe308f1 26 *ppQuery = NULL;
andrewboyson 130:9a5b8fe308f1 27
andrewboyson 130:9a5b8fe308f1 28 while (*p == ' ') //Move past any leading spaces
andrewboyson 130:9a5b8fe308f1 29 {
andrewboyson 130:9a5b8fe308f1 30 if (*p == 0) return;
andrewboyson 130:9a5b8fe308f1 31 p++;
andrewboyson 130:9a5b8fe308f1 32 }
andrewboyson 130:9a5b8fe308f1 33 *ppMethod = p; //Record the start of the method (GET or POST)
andrewboyson 130:9a5b8fe308f1 34
andrewboyson 130:9a5b8fe308f1 35 while (*p != ' ') //Move past the method
andrewboyson 130:9a5b8fe308f1 36 {
andrewboyson 130:9a5b8fe308f1 37 if (*p == 0) return;
andrewboyson 130:9a5b8fe308f1 38 p++;
andrewboyson 130:9a5b8fe308f1 39 }
andrewboyson 130:9a5b8fe308f1 40 *p = 0; //Terminate the method
andrewboyson 130:9a5b8fe308f1 41 p++; //Start at next character
andrewboyson 130:9a5b8fe308f1 42
andrewboyson 130:9a5b8fe308f1 43 while (*p == ' ') //Move past any spaces
andrewboyson 130:9a5b8fe308f1 44 {
andrewboyson 130:9a5b8fe308f1 45 if (*p == 0) return;
andrewboyson 130:9a5b8fe308f1 46 p++;
andrewboyson 130:9a5b8fe308f1 47 }
andrewboyson 130:9a5b8fe308f1 48 *ppPath = p; //Record the start of the path
andrewboyson 130:9a5b8fe308f1 49
andrewboyson 130:9a5b8fe308f1 50 while (*p != ' ') //Move past the path and query
andrewboyson 130:9a5b8fe308f1 51 {
andrewboyson 130:9a5b8fe308f1 52 if (*p == 0) return;
andrewboyson 130:9a5b8fe308f1 53 if (*p == '?')
andrewboyson 130:9a5b8fe308f1 54 {
andrewboyson 130:9a5b8fe308f1 55 *p = 0; //Terminate the path
andrewboyson 130:9a5b8fe308f1 56 *ppQuery = p + 1; //Record the start of the query
andrewboyson 130:9a5b8fe308f1 57 }
andrewboyson 130:9a5b8fe308f1 58 p++;
andrewboyson 130:9a5b8fe308f1 59 }
andrewboyson 130:9a5b8fe308f1 60 *p = 0; //Terminate the path or query
andrewboyson 130:9a5b8fe308f1 61 }
andrewboyson 130:9a5b8fe308f1 62 static void splitHeader(char* p, char** ppName, char** ppValue)
andrewboyson 130:9a5b8fe308f1 63 {
andrewboyson 130:9a5b8fe308f1 64 *ppName = p; //Record the start of the name
andrewboyson 130:9a5b8fe308f1 65 *ppValue = NULL;
andrewboyson 130:9a5b8fe308f1 66
andrewboyson 130:9a5b8fe308f1 67 while (*p != ':') //Loop to an ':'
andrewboyson 130:9a5b8fe308f1 68 {
andrewboyson 130:9a5b8fe308f1 69 if (!*p) return;
andrewboyson 130:9a5b8fe308f1 70 p++;
andrewboyson 130:9a5b8fe308f1 71 }
andrewboyson 130:9a5b8fe308f1 72 *p = 0; //Terminate the name by replacing the ':' with a NUL char
andrewboyson 130:9a5b8fe308f1 73 p++;
andrewboyson 130:9a5b8fe308f1 74 while (*p == ' ') //Move past any spaces
andrewboyson 130:9a5b8fe308f1 75 {
andrewboyson 130:9a5b8fe308f1 76 if (*p == 0) return;
andrewboyson 130:9a5b8fe308f1 77 p++;
andrewboyson 130:9a5b8fe308f1 78 }
andrewboyson 130:9a5b8fe308f1 79 *ppValue = p; //Record the start of the value
andrewboyson 130:9a5b8fe308f1 80 }
andrewboyson 130:9a5b8fe308f1 81 int HttpRequestRead(char *pData, int len, char** ppMethod, char** ppPath, char** ppQuery, char** ppLastModified, char** ppCookies, int* pContentLength)
andrewboyson 130:9a5b8fe308f1 82 {
andrewboyson 130:9a5b8fe308f1 83 char* pEnd = pData + len;
andrewboyson 130:9a5b8fe308f1 84 char* pThis = pData;
andrewboyson 130:9a5b8fe308f1 85 char* pNext = terminateThisAndGetNextLine(pThis, pEnd);
andrewboyson 130:9a5b8fe308f1 86 splitRequest(pThis, ppMethod, ppPath, ppQuery);
andrewboyson 130:9a5b8fe308f1 87
andrewboyson 130:9a5b8fe308f1 88 *ppLastModified = NULL; //Return NULL if no 'If-Modified-Since' line
andrewboyson 130:9a5b8fe308f1 89 *ppCookies = NULL; //Return NULL if no 'Cookie' line
andrewboyson 130:9a5b8fe308f1 90 *pContentLength = 0; //Return 0 if no 'Content-Length' line
andrewboyson 130:9a5b8fe308f1 91 while(pNext)
andrewboyson 130:9a5b8fe308f1 92 {
andrewboyson 130:9a5b8fe308f1 93 pThis = pNext;
andrewboyson 130:9a5b8fe308f1 94 pNext = terminateThisAndGetNextLine(pThis, pEnd);
andrewboyson 130:9a5b8fe308f1 95 if (*pThis == 0) break; //This line is empty ie no more headers
andrewboyson 130:9a5b8fe308f1 96 char* pName;
andrewboyson 130:9a5b8fe308f1 97 char* pValue;
andrewboyson 130:9a5b8fe308f1 98 splitHeader(pThis, &pName, &pValue);
andrewboyson 130:9a5b8fe308f1 99 if (HttpSameStrCaseInsensitive(pName, "If-Modified-Since")) *ppLastModified = pValue;
andrewboyson 130:9a5b8fe308f1 100 if (HttpSameStrCaseInsensitive(pName, "Cookie" )) *ppCookies = pValue;
andrewboyson 130:9a5b8fe308f1 101 if (HttpSameStrCaseInsensitive(pName, "Content-Length" )) *pContentLength = atoi(pValue);
andrewboyson 130:9a5b8fe308f1 102 }
andrewboyson 130:9a5b8fe308f1 103 if (pNext) return pNext - pData;
andrewboyson 130:9a5b8fe308f1 104 else return len;
andrewboyson 130:9a5b8fe308f1 105 }