Improve security when handling requests to download files#315
Conversation
jtjbrady
left a comment
There was a problem hiding this comment.
In case you're wondering why the unit test is failing on Windows but passing on Linux.
The first two unit tests start with /// this is unmodified by QDir::cleanPath on Windows (due to UNC paths I believe), on Linux this becomes a single /
So that the server performs the same on Linux and Windows I believe multiple leading slashes should be stripped in parseHeaders.
Thanks, I've been failing to get the output from the failing test on Windows (and I'm on Linux myself). |
Ok, so there are at least two locations in this file where cleanPath is called. One in: static HeadersMap parseHeaders(const QByteArray &headerData) line 86 - this produces the path which is eventually passed to everything else. So, what I was suggesting was ensuring there is at most one leading slash stored in cleanPath function in the headersMap("_path") by parseHeaders. It's annoying that cleanPath provides a different output on Windows. |
Ooops I meant to remove the cleanPath call in parseHeaders(). Are you sure about your assessment that QDir::cleanPath("///foo") returns ///foo on Windows? |
Here is my amazing program: On Linux: "/../world" |
|
qdir.cpp line 66 in rootLength has Windows specific rules to do with UNC paths. Those are normally //servername/ |
5f94ca1 to
623d1cf
Compare
|
Oh, I missed the fact that |
df49623 to
cbe67ae
Compare
|
OK, it passed. What do you think of this solution? |
|
More verbose than my regular expression solution, but much easier to understand. Given the use of QDir::cleanPath in parseHeaders I believe the whole test could probably be:
i.e. ensure the string starts with a / and the first section is not '..' |
|
Oh I see what you mean. We can't end up with /foo/bar/../.. after cleanPath. So there's no need to count going in and out, cleanPath has already cleaned as much as possible for us. I like your idea (simpler = less risks of errors), I'll change it that way. |
|
I've also just realised that this path contains the query string. So, the test should be only operating on the part before the query, e.g. path.section('?', 0, 0) So... Actually that's not necessary the path.section('?', 0, 0) is only necessary using your loop method. |
|
Good point. But we've already split out the query in parseHeaders, and then reassembled it, I think I'll rather store them split and reassemble afterwards in handleRequest. No point in parsing twice (with risks of slight differences). Also, since consecutive slashes have been cleaned up, we can just do |
|
I assume you mean |
cbe67ae to
60d7617
Compare
|
Yes of course, after the first test. Pushed. But too early, forgot about splitting the query. Doing too many things at the same time. |
I believe splitting the query was necessary only using your previous loop method, this method is looking for specific characters at the start of the string. |
|
misunderstanding, I mean the splitting of the query from the path ;) |
60d7617 to
61def2f
Compare
|
Are you OK with this version? Should I merge it? |
|
Only remaining issue I see is the one in the code review above. The unit test "leading_double_slash" is identical to "leading_triple_slash". |
|
Oh I haven't seen such a code review comment.... |
Make sure we never go outside the base directory Fixes #314
61def2f to
561fc4a
Compare
|
Ok, looks good to me. |
Make sure we never go outside the base directory
Fixes #314