Просмотр исходного кода

Sanitize uploaded filenames in upload example to prevent path traversal

The upload example wrote each uploaded file using the filename supplied
verbatim in the multipart Content-Disposition header. A client could set
that filename to an absolute path or one containing "../" components and
cause the server to create or overwrite files outside the working
directory.

Reduce each client-supplied filename to its base name and reject the
request with 400 Bad Request if the result is empty, ".", "..", or
still contains a path separator (including colon for Windows drive
letters).
Mario Limonciello 3 недель назад
Родитель
Сommit
76b54e7de4
1 измененных файлов с 32 добавлено и 2 удалено
  1. 32 2
      example/upload.cc

+ 32 - 2
example/upload.cc

@@ -8,6 +8,7 @@
 #include <fstream>
 #include <httplib.h>
 #include <iostream>
+
 using namespace httplib;
 using namespace std;
 
@@ -45,12 +46,41 @@ int main(void) {
          << "text file length: " << text_file.content.length() << endl
          << "text file name: " << text_file.filename << endl;
 
+    // Reduce a client-supplied filename to a safe base name, or return an
+    // empty string if it cannot be trusted (empty, ".", "..", or contains a
+    // path separator).
+    auto sanitize = [](const string &filename) -> string {
+      auto name = filename.substr(filename.find_last_of("/\\") + 1);
+      if (name.empty() || name == "." || name == ".." ||
+          name.find(':') != string::npos) {
+        return string();
+      }
+      return name;
+    };
+
+    const auto image_name = sanitize(image_file.filename);
+    const auto text_name = sanitize(text_file.filename);
+    if (image_name.empty() || text_name.empty()) {
+      res.status = StatusCode::BadRequest_400;
+      return;
+    }
+
     {
-      ofstream ofs(image_file.filename, ios::binary);
+      ofstream ofs(image_name, ios::binary);
+      if (!ofs) {
+        res.status = StatusCode::InternalServerError_500;
+        res.set_content("Failed to write image file", "text/plain");
+        return;
+      }
       ofs << image_file.content;
     }
     {
-      ofstream ofs(text_file.filename);
+      ofstream ofs(text_name);
+      if (!ofs) {
+        res.status = StatusCode::InternalServerError_500;
+        res.set_content("Failed to write text file", "text/plain");
+        return;
+      }
       ofs << text_file.content;
     }