3

I'd like to use $wp_filesystem which seems to be the recommended way to manipulate file system objects in WordPress but compare this:

plain PHP code:

mkdir('abc');

WP Filesystem API code:

$url = wp_nonce_url('plugins.php');
if (false === ($creds = request_filesystem_credentials($url, '', false, false, null) ) ) {
    echo "Could not create filesystem credentials";
    return;
}

if ( ! WP_Filesystem($creds) ) {
    request_filesystem_credentials($url, '', true, false, null);
    echo "Filesystem credentials were not available";
    return;
}

$wp_filesystem->mkdir('abc', true);

This is a bit unwieldy and maybe I'm getting something wrong but isn't there a more convenient way to execute methods on $wp_filesystem? I tried to leave the credentials code out but in that case, the filesystem command didn't work.

1 Answer 1

6

No, there is not a more convenient way.

The thing is, your first example is insecure on the most common hosting systems because the directory will be "owned" by whatever user the webserver itself is running as. Thus, anybody else able to execute code on that same webserver will be able to access it, write to it, changes files in it, and so on.

Credentials are necessary to ensure that the files are owned by the correct person, preventing them from being accessed by others on the same server.

Additional info because the comments seem to need it:

On a "standard" shared hosting configuration, or even on some VPS hosting systems, the webserver is running as a different user than the person who actually owns the files. So, my WordPress install files might be owned by "otto", but the webserver maybe runs under the "apache" account.

This means that when the WordPress code is running, it's typically running as the "apache" user. Any files it creates will also be owned by "apache", not by "otto". Furthermore, the "apache" account is necessarily limited. It may not have the ability to write files in my web directories at all, or it may not have the ability to chown the files to be owned by the proper "otto" user. This is all for security reasons, it should not have those abilities.

The WP_Filesystem detects when this is the case, and then will display a form to the user asking for FTP credentials. This is what the request_filesystem_credentials call actually does: It performs that test and then generates a form for the user when necessary. The user puts in their information, and using that, on the next submit, the request_filesystem_credentials call can check if it can connect back to itself (loopback, sorta) via FTP.

See, when I create a file via FTP, then I'm connected as me, so the resulting file is owned by "otto". Using this mechanism, the WP_Filesystem can create files as the correct user even though it's running as "apache". Those credentials are thus necessary and yes, you must ask the user for them. Simply naively creating files and directories using normal PHP methods can lead to a security issue, especially on shared hosting.

On a shared host, other people have accounts on the same machine. They are running their code using the same webserver processes. And that code runs as "apache" too. So, if I have directories and files owned by "apache", then other people can run their code as "apache" and modify my files. That's a problem. Having the files owned by me and not "apache" prevents that.

Now, on some of the most common shared hosting systems, you'll find that making the request_filesystem_credentials call actually doesn't pop up a form. Instead, it simply returns true and the WP_Filesystem code carries on. This happens when a hosting system is running with a configuration known as "setuid" or "suphp".

In a setuid configuration, the webserver runs as "apache" or whatever, but the PHP process that it spawns to handle a request sets its own user/owner to be the same as the owner of the PHP file that it initially runs. So when the php process runs, and loads the initial WordPress index.php file (or whatever file), it sees that the file is owned by "otto" and so it sets it own user account to "otto" for that particular run.

A lot of shared hosting providers do this configuration because it is actually more secure for that case. If the php process runs as the user account, then it is not "apache" any more and cannot access files in other people's accounts. It can only access the files for the account it's supposed to have access to. As a nice side effect, this means that the request_filesystem_credentials call performs its test and finds that a) yes it can write files and b) those files will be owned by the correct user, because the user of the process is now set to the same as the owner of the files. In that case, the "direct" mode is used, request_filesystem_credentials returns true, and no form is displayed to the user for FTP credentials.

Note that setuid methods like this are actually less secure on non-shared hosting accounts. When there is only one web user, then there's no need to do setuid to protect other web users on the same server. So on VPS hosting and similar, this setup is not as common, and requiring FTP credentials is commonplace. This is more secure because even if an attacker can cause the system to execute code, they may not be able to have that code modify any files because it's not running as the correct process.

Security is complex. The WP_Filesystem is fundamentally a security thing, and you should use it if you need to manipulate files in the installation. And yes, sometimes this means you need to display a credentials form. I suggest coping with it, because anything else is a potential security risk that you should not simply wipe away just because it's somewhat unpleasant.

6
  • I thought it was about making a consistent interface whether you're hosted on a shell account or an FTP account, not file ownership?
    – Rup
    Commented Aug 13, 2014 at 9:30
  • Um, no. It's about file ownership, almost entirely. The WP_Filesystem was created to let WP update itself, and for that to happen properly, it needs to be sure that it doesn't introduce any security issues in the process. The WP_Filesystem is a fundamentally a security thing.
    – Otto
    Commented Aug 13, 2014 at 10:28
  • The confusing part is the request_filesystem_credentials() method which is described as "Displays a form to the user to request for their FTP/SSH details in order to connect to the filesystem" - that is not something I want to do at all. I've noticed that there is the wp_filesystem() method, can it be used to make the code in the OP simpler? Or maybe I could hide those ugly 10 lines behind some custom function? What do you guys do in your plugins? Commented Aug 13, 2014 at 10:56
  • Borek: Getting some form of credentials from the user is necessary if they have a setup where WP cannot write files directly with the proper ownership. There is no magic way to write files and give them ownership without the credentials of the user to whom the files will be owned by. If their setup allows for direct writing (meaning that the php process is running as the user and not as a special webserver user account), then this method will simply return true here and no form would thus be displayed to the user.
    – Otto
    Commented Aug 13, 2014 at 12:50
  • As for what I do in my plugins: That very code. See plugins.svn.wordpress.org/pluginception/trunk/pluginception.php
    – Otto
    Commented Aug 13, 2014 at 12:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.