I really like your question and think it is interestering, thus I am going to attempt to answer it. If you feel like I should put more detail on certain aspects of the answer, feel free to comment and I will expand the answer as good as I can.
After you elaborated in the comments it appears your question boils down to:
Is it unsafe to dynamically check if a directory exists, depending on user input?
To answer this we must look at multiple aspects of security but first and foremost ask ourselves what "safe" really means.
What is safety?
What I want to point out here is that safety is always a ratio between "work done to compromise the system" and "damage that can be done to the system by doing so". I.e., if you put a lot of effort into it (for arguments sake, lets say infinite effort), you would most likely break every system sooner or later (that is, with either more or with less effort).
Having said that, we should tighten the scope of this topic to PHP. As you may or may not know, PHP is mostly written in C and C++, which both have their own flaws on top of the issues that might exist with PHP on its own (which would be because of the authors of PHP did miss something). I am only mentioning this to point out that there are several layers of security to consider and thus, answers of the sorts "is this safe" should never be taken for 100% answers.
Is it "safe" to dynamically check for folders by user input?
It depends!
Before getting into details, please note that whether:
- you build your whitelist dynamically from user input or
- you dynamically check if there is a folder with a name from user input
can be considered the same thing from a security standpoint and only the timing of flaw would be different.
Now on to the details, and as I already said: It depends! There are plenty of possible implementations that would really open the gates to every evil input, such as running system commands to check if a folder exists, here is an example:
$input = $_GET['folder']; // let's say this is called like /?folder=foo
exec("test -d " . $input, $output, $return);
$doesFolderExist = ($return == 0); // variable would be true if folder exists
This is one way to implement whether a folder exists, however it is a deliberately stupid one to demonstrate how one could be going wrong about this. Why is it stupid? It is widely open for Command Injection. For example, an attacker could call the URL like /?folder=foo;rm -rf /
and the servers entire disk would possibly be deleted.
Back to reasonable solutions
After I rambled about a bit on how nothing is entirely safe above, there are certainly some ways which - at least from my point of view - can be considered safe enough to be trusted with user input. One option would be to use glob()
and check whether the folder is there, but I think this is even unnecessarily complicated.
For your specific use case I think a simple file_exists()
check should suffice and not open a gate to evil user input, let's revisit the example from above:
$input = $_GET['folder']; // again, imagine this is called like /?folder=foo
$doesFolderExist = file_exists(__DIR__ . $input); // variable would be true if folder exists
As you can see I added the __DIR__
constant to make checking of folder existance relative to the current PHP file, you might have to adjust that depending on your use case.
There is however one pitfall, so please do not use this solution as it is, but keep reading!
Nifty attackers might figure out that you are using a relative path and try and sneak a weird parameter in that cascades through your file system to check whether certain things are there or not. For example, an attacker might call the URL like /?folder=../../home/admin
which could possibly give him some insight on whether there is a user with the name "admin" in this system or not.
The possible use cases for this are plenty, which is why such file/directory checks with user input should always be limited to a very specific scope. For example, you could make sure that walking folders up is not possible by replacing away the syntax, and therefore the final solution would look like this:
$input = $_GET['folder']; // attacker might call /?folder=../../user/foo
$input = str_replace('../', '', $input); // sanitize
$doesFolderExist = file_exists(__DIR__ . $input); // variable would be true if folder exists
This way the attacker would "only" know if within the same directory where your PHP file is there is a subfolder named user/foo
but not actually find out if there is a system user with the name "foo". Of course more sanitization is always possible depending on your expected structure. For example, if you only allow one level of subfolders, you could replace away (same way as in the example) all the slashes in the user input.
In a nutshell
I hope I could point out that security is never absolute but as long as you take the required measures you can be pretty much on the safe side, here are some ground rules you should (almost) always follow:
- All input is evil, treat it as such
- Try and think of ways to break your own solution
- When in doubt, expect the worst possible scenario
Hope this helps!