Sanitize uploaded filenames in upload example to prevent path traversal#2496
Sanitize uploaded filenames in upload example to prevent path traversal#2496superm1 wants to merge 1 commit into
Conversation
|
Thanks for the fix — the upload example is easy to copy-paste, so sanitizing the client-supplied filename here is worthwhile. A few points before merging: 1. This breaks the example build (must fix)
Since the library itself targets C++11, I'd prefer avoiding 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;
};This also handles the POSIX case uniformly: 2. The
3. Minor: consider rejecting On Windows, a name like Everything else looks good — writing into a dedicated |
c050d8e to
fe91f3f
Compare
|
Adjusted, thanks! |
|
Thanks, but there is another issue when writing into uploads/ assumes that directory already exists. It doesn't, and nothing in this PR creates it. If you run the example fresh, Before this PR, files were written directly into the cwd, so this dependency on a pre-existing directory is new here. It's not a pre-existing issue. So it would be better to actually make sure that directory exists rather than assume it. Otherwise, users would be confused. You could do either:
Thanks! |
fe91f3f to
15a1a3d
Compare
|
Thanks, I've added an error code for this case. |
|
|
Gah. |
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, reject the request with 400 Bad Request if the result is empty, ".", "..", or still contains a path separator, and write the files into a dedicated "uploads" directory.
15a1a3d to
6f97046
Compare
|
I guess we can do something like this where we just call |
|
The Since this is just an example, I'd like to keep it minimal. Please drop 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;
}Then |
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.This reduces each client-supplied filename to its base name, rejects the request with 400 Bad Request if the result is empty,
.,.., or still contains a path separator, and writes the files into a dedicateduploadsdirectory.