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 109:3e82f62c7e1f 1 #include "http.h"
andrewboyson 109:3e82f62c7e1f 2 #include "web-server-base.h"
andrewboyson 112:f29bb9b99059 3 #include "web-server-this.h"
andrewboyson 110:8ab752842d25 4 #include "web.h"
andrewboyson 110:8ab752842d25 5 #include "web-pages-base.h"
andrewboyson 130:9a5b8fe308f1 6 #include "http-connection.h"
andrewboyson 130:9a5b8fe308f1 7 #include "log.h"
andrewboyson 109:3e82f62c7e1f 8 #include "mstimer.h"
andrewboyson 109:3e82f62c7e1f 9
andrewboyson 109:3e82f62c7e1f 10 #define LOGIN_DELAY_MS 200
andrewboyson 109:3e82f62c7e1f 11
andrewboyson 110:8ab752842d25 12 #define DO_LOGIN DO_SERVER + 0
andrewboyson 110:8ab752842d25 13
andrewboyson 130:9a5b8fe308f1 14 bool WebTrace = false;
andrewboyson 130:9a5b8fe308f1 15
andrewboyson 130:9a5b8fe308f1 16 int WebDecideWhatToDo(char *pPath, char* pLastModified)
andrewboyson 110:8ab752842d25 17 {
andrewboyson 110:8ab752842d25 18 if (HttpSameStr(pPath, "/login")) return DO_LOGIN;
andrewboyson 110:8ab752842d25 19
andrewboyson 110:8ab752842d25 20 int todo;
andrewboyson 112:f29bb9b99059 21 todo = WebServerBaseDecideWhatToDo(pPath, pLastModified); if (todo != DO_NOT_FOUND) return todo;
andrewboyson 112:f29bb9b99059 22 todo = WebServerThisDecideWhatToDo(pPath, pLastModified); if (todo != DO_NOT_FOUND) return todo;
andrewboyson 110:8ab752842d25 23 return DO_NOT_FOUND;
andrewboyson 110:8ab752842d25 24 }
andrewboyson 130:9a5b8fe308f1 25 int WebHandleQuery(char* pQuery, char* pCookies, int* pTodo, uint32_t* pDelayUntil) //return -1 on stop; 0 on continue
andrewboyson 110:8ab752842d25 26 {
andrewboyson 130:9a5b8fe308f1 27 //If what to do is NOTHING, NOT_FOUND or NOT_MODIFIED then no query or post will be valid so stop now
andrewboyson 130:9a5b8fe308f1 28 if (*pTodo < DO_LOGIN) return -1;
andrewboyson 130:9a5b8fe308f1 29
andrewboyson 130:9a5b8fe308f1 30 //If what to do is LOGIN then the user has just returned the login form
andrewboyson 130:9a5b8fe308f1 31 if (*pTodo == DO_LOGIN)
andrewboyson 110:8ab752842d25 32 {
andrewboyson 130:9a5b8fe308f1 33 WebLoginQuery(pQuery); //Read the password and the original location
andrewboyson 130:9a5b8fe308f1 34 if (WebLoginQueryPasswordOk)
andrewboyson 130:9a5b8fe308f1 35 {
andrewboyson 130:9a5b8fe308f1 36 if (!WebLoginSessionIdIsSet()) //If there isn't a session id already
andrewboyson 130:9a5b8fe308f1 37 {
andrewboyson 130:9a5b8fe308f1 38 WebLoginSessionIdNew(); //Create a new session id
andrewboyson 130:9a5b8fe308f1 39 }
andrewboyson 130:9a5b8fe308f1 40 *pTodo = WebLoginOriginalToDo; //Load the original todo and SEND_SESSION_ID
andrewboyson 130:9a5b8fe308f1 41 *pTodo += DO_SEND_SESSION_ID;
andrewboyson 130:9a5b8fe308f1 42 }
andrewboyson 130:9a5b8fe308f1 43 *pDelayUntil = MsTimerCount + LOGIN_DELAY_MS; //To prevent brute forcing the hash delay the reply to the login
andrewboyson 130:9a5b8fe308f1 44 return -1; //Either way no query or post will be valid
andrewboyson 110:8ab752842d25 45 }
andrewboyson 130:9a5b8fe308f1 46
andrewboyson 130:9a5b8fe308f1 47 //Have a normal request so authenticate
andrewboyson 130:9a5b8fe308f1 48 if (!WebLoginCookiesContainValidSessionId(pCookies))
andrewboyson 130:9a5b8fe308f1 49 {
andrewboyson 130:9a5b8fe308f1 50 WebLoginOriginalToDo = *pTodo; //Record the original destination for redirection
andrewboyson 130:9a5b8fe308f1 51 *pTodo = DO_LOGIN;
andrewboyson 130:9a5b8fe308f1 52 return -1; //Ignore any query or post as the user is not authenticated
andrewboyson 130:9a5b8fe308f1 53 }
andrewboyson 130:9a5b8fe308f1 54
andrewboyson 130:9a5b8fe308f1 55 if (WebServerBaseHandleQuery(*pTodo, pQuery)) return 0;
andrewboyson 130:9a5b8fe308f1 56 if (WebServerThisHandleQuery(*pTodo, pQuery)) return 0;
andrewboyson 130:9a5b8fe308f1 57 return 0;
andrewboyson 110:8ab752842d25 58 }
andrewboyson 130:9a5b8fe308f1 59 void WebHandlePost(int todo, int contentLength, int contentStart, int size, char* pRequestStream, uint32_t positionInRequestStream, bool* pComplete)
andrewboyson 110:8ab752842d25 60 {
andrewboyson 112:f29bb9b99059 61 if (WebServerBasePost(todo, contentLength, contentStart, size, pRequestStream, positionInRequestStream, pComplete)) return;
andrewboyson 112:f29bb9b99059 62 if (WebServerThisPost(todo, contentLength, contentStart, size, pRequestStream, positionInRequestStream, pComplete)) return;
andrewboyson 111:aaa858678e34 63 *pComplete = true;
andrewboyson 110:8ab752842d25 64 }
andrewboyson 110:8ab752842d25 65
andrewboyson 130:9a5b8fe308f1 66 void WebAddResponse(int todo)
andrewboyson 109:3e82f62c7e1f 67 {
andrewboyson 109:3e82f62c7e1f 68 //Check if todo includes the need to send a cookie
andrewboyson 109:3e82f62c7e1f 69 if (todo >= DO_SEND_SESSION_ID)
andrewboyson 109:3e82f62c7e1f 70 {
andrewboyson 109:3e82f62c7e1f 71 HttpOkCookieName = WebLoginSessionNameGet();
andrewboyson 109:3e82f62c7e1f 72 HttpOkCookieValue = WebLoginSessionIdGet();
andrewboyson 109:3e82f62c7e1f 73 HttpOkCookieMaxAge = WebLoginSessionNameLife();
andrewboyson 109:3e82f62c7e1f 74 todo -= DO_SEND_SESSION_ID;
andrewboyson 109:3e82f62c7e1f 75 }
andrewboyson 109:3e82f62c7e1f 76 else
andrewboyson 109:3e82f62c7e1f 77 {
andrewboyson 109:3e82f62c7e1f 78 HttpOkCookieName = NULL;
andrewboyson 109:3e82f62c7e1f 79 HttpOkCookieValue = NULL;
andrewboyson 109:3e82f62c7e1f 80 HttpOkCookieMaxAge = -1;
andrewboyson 109:3e82f62c7e1f 81 }
andrewboyson 109:3e82f62c7e1f 82
andrewboyson 130:9a5b8fe308f1 83 //Try all the base modules
andrewboyson 130:9a5b8fe308f1 84 switch (todo)
andrewboyson 130:9a5b8fe308f1 85 {
andrewboyson 130:9a5b8fe308f1 86 case DO_LOGIN: WebLoginHtml (); return;
andrewboyson 130:9a5b8fe308f1 87 case DO_NOT_FOUND: HttpNotFound (); return;
andrewboyson 130:9a5b8fe308f1 88 case DO_NOT_MODIFIED: HttpNotModified (); return;
andrewboyson 130:9a5b8fe308f1 89 }
andrewboyson 122:cd3f391ac8aa 90
andrewboyson 130:9a5b8fe308f1 91 //If not called then call the derived (child) module
andrewboyson 130:9a5b8fe308f1 92 if (WebServerBaseReply(todo)) return;
andrewboyson 130:9a5b8fe308f1 93 if (WebServerThisReply(todo)) return;
andrewboyson 109:3e82f62c7e1f 94 }
andrewboyson 109:3e82f62c7e1f 95
andrewboyson 130:9a5b8fe308f1 96 void WebInit()
andrewboyson 130:9a5b8fe308f1 97 {
andrewboyson 130:9a5b8fe308f1 98 WebLoginInit();
andrewboyson 109:3e82f62c7e1f 99 }