From a7ced9cabbe266c23b895d72b6c8df8a0eee02e5 Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Tue, 7 Jun 2016 05:09:05 +0300 Subject: [PATCH] make HTTP Update Server more secure (#2104) * make HTTP Update Server more secure * added option for authentication * added option to change the url for upload * move to overloaded setup * remove delay in both examples * Get better result responses * fix strings interesting, the meta did not refresh if the successResponse is put in "R" --- .../SecureWebUpdater/SecureWebUpdater.ino | 45 +++++++++++++++++++ .../examples/WebUpdater/WebUpdater.ino | 1 - .../src/ESP8266HTTPUpdateServer.cpp | 39 +++++++++++----- .../src/ESP8266HTTPUpdateServer.h | 23 +++++++++- 4 files changed, 94 insertions(+), 14 deletions(-) create mode 100644 libraries/ESP8266HTTPUpdateServer/examples/SecureWebUpdater/SecureWebUpdater.ino diff --git a/libraries/ESP8266HTTPUpdateServer/examples/SecureWebUpdater/SecureWebUpdater.ino b/libraries/ESP8266HTTPUpdateServer/examples/SecureWebUpdater/SecureWebUpdater.ino new file mode 100644 index 000000000..da6f0bec5 --- /dev/null +++ b/libraries/ESP8266HTTPUpdateServer/examples/SecureWebUpdater/SecureWebUpdater.ino @@ -0,0 +1,45 @@ +/* + To upload through terminal you can use: curl -F "image=@firmware.bin" esp8266-webupdate.local/update +*/ + +#include +#include +#include +#include +#include + +const char* host = "esp8266-webupdate"; +const char* update_path = "/firmware"; +const char* update_username = "admin"; +const char* update_password = "admin"; +const char* ssid = "........"; +const char* password = "........"; + +ESP8266WebServer httpServer(80); +ESP8266HTTPUpdateServer httpUpdater; + +void setup(void){ + + Serial.begin(115200); + Serial.println(); + Serial.println("Booting Sketch..."); + WiFi.mode(WIFI_AP_STA); + WiFi.begin(ssid, password); + + while(WiFi.waitForConnectResult() != WL_CONNECTED){ + WiFi.begin(ssid, password); + Serial.println("WiFi failed, retrying."); + } + + MDNS.begin(host); + + httpUpdater.setup(&httpServer, update_path, update_username, update_password); + httpServer.begin(); + + MDNS.addService("http", "tcp", 80); + Serial.printf("HTTPUpdateServer ready! Open http://%s.local%s in your browser and login with username '%s' and password '%s'\n", host, update_path, update_username, update_password); +} + +void loop(void){ + httpServer.handleClient(); +} diff --git a/libraries/ESP8266HTTPUpdateServer/examples/WebUpdater/WebUpdater.ino b/libraries/ESP8266HTTPUpdateServer/examples/WebUpdater/WebUpdater.ino index 13798adbf..53fc358db 100644 --- a/libraries/ESP8266HTTPUpdateServer/examples/WebUpdater/WebUpdater.ino +++ b/libraries/ESP8266HTTPUpdateServer/examples/WebUpdater/WebUpdater.ino @@ -39,5 +39,4 @@ void setup(void){ void loop(void){ httpServer.handleClient(); - delay(1); } diff --git a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp index ada6c0241..6ef4f93ae 100644 --- a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp +++ b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp @@ -7,34 +7,41 @@ const char* ESP8266HTTPUpdateServer::_serverIndex = -R"(
+R"(
)"; +const char* ESP8266HTTPUpdateServer::_failedResponse = R"(Update Failed!)"; +const char* ESP8266HTTPUpdateServer::_successResponse = "Update Success! Rebooting..."; ESP8266HTTPUpdateServer::ESP8266HTTPUpdateServer(bool serial_debug) { _serial_output = serial_debug; _server = NULL; + _username = NULL; + _password = NULL; + _authenticated = false; } -void ESP8266HTTPUpdateServer::setup(ESP8266WebServer *server) +void ESP8266HTTPUpdateServer::setup(ESP8266WebServer *server, const char * path, const char * username, const char * password) { _server = server; + _username = (char *)username; + _password = (char *)password; // handler for the /update form page - _server->on("/update", HTTP_GET, [&](){ - _server->sendHeader("Connection", "close"); - _server->sendHeader("Access-Control-Allow-Origin", "*"); + _server->on(path, HTTP_GET, [&](){ + if(_username != NULL && _password != NULL && !_server->authenticate(_username, _password)) + return _server->requestAuthentication(); _server->send(200, "text/html", _serverIndex); }); // handler for the /update form POST (once file upload finishes) - _server->on("/update", HTTP_POST, [&](){ - _server->sendHeader("Connection", "close"); - _server->sendHeader("Access-Control-Allow-Origin", "*"); - _server->send(200, "text/html", (Update.hasError())?"FAIL":"OK"); + _server->on(path, HTTP_POST, [&](){ + if(!_authenticated) + return _server->requestAuthentication(); + _server->send(200, "text/html", Update.hasError() ? _failedResponse : _successResponse); ESP.restart(); },[&](){ // handler for the file upload, get's the sketch bytes, and writes @@ -43,6 +50,14 @@ void ESP8266HTTPUpdateServer::setup(ESP8266WebServer *server) if(upload.status == UPLOAD_FILE_START){ if (_serial_output) Serial.setDebugOutput(true); + + _authenticated = (_username == NULL || _password == NULL || _server->authenticate(_username, _password)); + if(!_authenticated){ + if (_serial_output) + Serial.printf("Unauthenticated Update\n"); + return; + } + WiFiUDP::stopAll(); if (_serial_output) Serial.printf("Update: %s\n", upload.filename.c_str()); @@ -50,20 +65,20 @@ void ESP8266HTTPUpdateServer::setup(ESP8266WebServer *server) if(!Update.begin(maxSketchSpace)){//start with max available size if (_serial_output) Update.printError(Serial); } - } else if(upload.status == UPLOAD_FILE_WRITE){ + } else if(_authenticated && upload.status == UPLOAD_FILE_WRITE){ if (_serial_output) Serial.printf("."); if(Update.write(upload.buf, upload.currentSize) != upload.currentSize){ if (_serial_output) Update.printError(Serial); } - } else if(upload.status == UPLOAD_FILE_END){ + } else if(_authenticated && upload.status == UPLOAD_FILE_END){ if(Update.end(true)){ //true to set the size to the current progress if (_serial_output) Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize); } else { if (_serial_output) Update.printError(Serial); } if (_serial_output) Serial.setDebugOutput(false); - } else if(upload.status == UPLOAD_FILE_ABORTED){ + } else if(_authenticated && upload.status == UPLOAD_FILE_ABORTED){ Update.end(); if (_serial_output) Serial.println("Update was aborted"); } diff --git a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.h b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.h index 5054af1e6..fbe1d211d 100644 --- a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.h +++ b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.h @@ -9,9 +9,30 @@ class ESP8266HTTPUpdateServer bool _serial_output; ESP8266WebServer *_server; static const char *_serverIndex; + static const char *_failedResponse; + static const char *_successResponse; + char * _username; + char * _password; + bool _authenticated; public: ESP8266HTTPUpdateServer(bool serial_debug=false); - void setup(ESP8266WebServer *server=NULL); + + void setup(ESP8266WebServer *server) + { + setup(server, NULL, NULL); + } + + void setup(ESP8266WebServer *server, const char * path) + { + setup(server, path, NULL, NULL); + } + + void setup(ESP8266WebServer *server, const char * username, const char * password) + { + setup(server, "/update", username, password); + } + + void setup(ESP8266WebServer *server, const char * path, const char * username, const char * password); };