Skip to content

Commit 450c640

Browse files
committed
fix(csrf): Fix SCRF vulnerability in WebUpdate.ino
1 parent 6e60f2f commit 450c640

File tree

1 file changed

+35
-5
lines changed

1 file changed

+35
-5
lines changed

libraries/WebServer/examples/WebUpdate/WebUpdate.ino

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,16 @@
1111
const char *host = "esp32-webupdate";
1212
const char *ssid = "........";
1313
const char *password = "........";
14+
const char * authUser = "admin";
15+
const char * authPass = "admin";
1416

1517
WebServer server(80);
1618
const char *serverIndex =
1719
"<form method='POST' action='/update' enctype='multipart/form-data'><input type='file' name='update'><input type='submit' value='Update'></form>";
1820

21+
const char * csrfHeaders[2] = {"Origin", "Host"};
22+
static bool authenticated = false;
23+
1924
void setup(void) {
2025
Serial.begin(115200);
2126
Serial.println();
@@ -24,37 +29,62 @@ void setup(void) {
2429
WiFi.begin(ssid, password);
2530
if (WiFi.waitForConnectResult() == WL_CONNECTED) {
2631
MDNS.begin(host);
32+
server.collectHeaders(csrfHeaders, 2);
2733
server.on("/", HTTP_GET, []() {
34+
if (!server.authenticate(authUser, authPass)) {
35+
return server.requestAuthentication();
36+
}
2837
server.sendHeader("Connection", "close");
2938
server.send(200, "text/html", serverIndex);
3039
});
3140
server.on(
3241
"/update", HTTP_POST,
3342
[]() {
43+
if (!authenticated) {
44+
return server.requestAuthentication();
45+
}
3446
server.sendHeader("Connection", "close");
35-
server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
36-
ESP.restart();
47+
if (Update.hasError()) {
48+
server.send(200, "text/plain", "FAIL");
49+
} else {
50+
server.send(200, "text/plain", "Success! Rebooting...");
51+
delay(500);
52+
ESP.restart();
53+
}
3754
},
3855
[]() {
3956
HTTPUpload &upload = server.upload();
4057
if (upload.status == UPLOAD_FILE_START) {
4158
Serial.setDebugOutput(true);
59+
authenticated = server.authenticate(authUser, authPass);
60+
if (!authenticated) {
61+
Serial.println("Authentication fail!");
62+
return;
63+
}
64+
String origin = server.header(String(csrfHeaders[0]));
65+
String host = server.header(String(csrfHeaders[1]));
66+
String expectedOrigin = String("http://") + host;
67+
if (origin != expectedOrigin) {
68+
Serial.printf("Wrong origin received! Expected: %s, Received: %s\n", expectedOrigin.c_str(), origin.c_str());
69+
authenticated = false;
70+
}
71+
4272
Serial.printf("Update: %s\n", upload.filename.c_str());
4373
if (!Update.begin()) { //start with max available size
4474
Update.printError(Serial);
4575
}
46-
} else if (upload.status == UPLOAD_FILE_WRITE) {
76+
} else if (authenticated && upload.status == UPLOAD_FILE_WRITE) {
4777
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
4878
Update.printError(Serial);
4979
}
50-
} else if (upload.status == UPLOAD_FILE_END) {
80+
} else if (authenticated && upload.status == UPLOAD_FILE_END) {
5181
if (Update.end(true)) { //true to set the size to the current progress
5282
Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
5383
} else {
5484
Update.printError(Serial);
5585
}
5686
Serial.setDebugOutput(false);
57-
} else {
87+
} else if(authenticated) {
5888
Serial.printf("Update Failed Unexpectedly (likely broken connection): status=%d\n", upload.status);
5989
}
6090
}

0 commit comments

Comments
 (0)