The

You know you like it.

PHP Applications & Filesystem Permissions: The Definitive Guide

| Comments

Recently, I read an article on the Sucuri Blog about the fundamentals of filesystem permissions, and how to apply some these fundamental concepts to securing web applications. When I noticed the article, I was quite happy to see that this issue was getting what I believed to be some much needed attention. As a security administrator working for a mid-sized web hosting company, I have found filesystem permissions to be one of the most misunderstood fundamentals of managing web applications. This misunderstanding can have colossal consequences when paired with unpatched, vulnerable web applications.

Having been the first responder to the ensuing incidents (which I assure you, are not pretty), I was hoping Sucuri’s post would be the champion of that cause which I have recently found so near and dear to my heart. While it is an excellent overview of UNIX filesystem permissions for someone who has no knowledge of such things, it stopped short of answering what, in my mind, is the real question that needs to be answered about filesystem permissions. Principally:

How do I decide what modes to apply to which filesystem resources?

With the aforementioned blog article having stopped short of answering that question, I decided to take it upon myself to build on the article, and deliver the unambiguous answer which so badly needs delivering. So without further adieu, we will explore the question.

It is important to note that we will be answering this question within a very specific scope. This article was inspired by a post on a web application security blog, and is being written by a web hosting administrator. So it should come as no shock that we will specifically be discussing this question as it regards web applications. More specifically, we will be addressing how it regards PHP web applications. I don’t care that there are a million and one web technologies that are harder/better/faster/stronger than PHP; the vast majority of existing web applications on the internet are still PHP applications, and it isn’t even close. So Python/Node/Ruby/whatever diehards, feel free to close the tab if the focus of the article will be a point of insurmountable bitterness to you.

In any case, many points discussed in this article will not be difficult to extrapolate and apply to other types of environments. So feel equally free to just suck it up and read on.

Do Your Homework

I want to be clear: This post will not teach you the fundamentals of UNIX filesystem permissions. As I previously mentioned, the Sucuri blog article which inspired this post already does a great job of this. I will not repeat here what it’s author has already written. Go read it.

Building on the Basics

In case you’re coming fresh off of the basics, there may be some terms and concepts introduced in this article which you haven’t seen yet elsewhere.

What’s a Mode?

A mode is the permissions bits which are set on a filesystem resource. For example, if you execute chmod 755 /my/stupid/directory/, you have just set the mode on that directory to 755.

Processes and Their Users

Since you’ve done your homework already (…right?), you’re well aware that every filesystem resource is owned by a particular user, and by a particular group. If you’re on a command line, viewing the owning user and group of these resources is simple enough.

1
2
3
4
5
$ ls -l /tmp/my-stupid-directory/
total 0
-rw-r--r-- 1 james users 0 Sep  1 19:29 a
-rw-r--r-- 1 james users 0 Sep  1 19:29 b
# Looks like these files are owned by user "james" and group "users"

Where we need to expand on this concept, is in coming to understand that just as every filesystem resource must be owned by a particular user and group, every single process on the server must be executed as a particular user and group. The executing user and group can also be viewed using a simple command.

1
2
3
4
# I want to know which user and group the "bash" process is currently executing as
$ ps axo pid,user,group,command | grep '[b]ash'
 1101 james    users    /bin/bash
# It's "james"/"users"!

Consequently, an executing process has access to all of the filesystem resources which the user and group it is executing as have access to. This concept is foundational to what will be discussed in the remainder of the article. If you didn’t understand, stop right now and go do more homework until you understand it. Otherwise, your time will be wasted in reading on.

The Definite Wrong Answer

Many of us (and by “us” I really mean millenials) may have been told at some point in our lives, “There is no such thing as a stupid question.” Well whether you believe that or not, I’m here to tell you there is definitely such a thing as a stupid answer. Unfortunately, there are far too many of them out there in response to questions about filesystem permissions. Before we go down the rabbit hole of determining good filesystem permissions, here are a couple of very simple cardinal rules about recognizing bad filesystem permissions.

  1. If your application/module/theme/whatever documentation tells you to set the permissions of a file or directory to 777… throw it in the garbage. Seriously. As soon as you see any instruction resembling chmod 777, stop reading, pick up the document, and put it straight in the trash can. Possibly even print a physical copy of it, so you can do it the indignity of being placed in a real trash can, with real trash, where it belongs. Then possibly consider not using that piece of software, because its authors either don’t understand or don’t care about the fundamentals of application security.
  2. 666 is as insecure as it is unholy. Same rules apply as do to 777. Which is to say, never set this mode. EVER. There are no exceptions.

This is one point that the Sucuri article absolutely nailed on the head, and I will break my promise about not repeating in order to emphasize. These basic rules are crucial to preventing small infections from turning into massive, server-wide malware outbreaks. You would think and hope that these rules seem so appallingly obvious that there would be no need to state them. However, at the intersection of hope and reality, the obvious is not equally obvious to everyone. So remember to take a moment every now and then to remind yourself to never ever do these things.

The Definite Right Answer

At the outset of the article, I posed that the question which we all must learn to answer is, “How do I decide what modes to apply to which filesystem resources?”

Some seasoned administrators might roll their eyes at this question. “It’s too open ended,” they might say. “It depends on one million and one things,” they might say. To which the response would have to be, “Well, that’s right… and it’s not.”

It is certainly true that a multitude of factors may influence what mode you finally choose to set on a particular file or directory. However, it is certainly also true that this is not an open ended question. It is a question which has a single consistently correct answer.

We can always decide what modes to apply to each resource by applying the principle of least privilege.

That is, the mode of a file or directory should grant the absolute minimum level of access required in order for the application to function.

Now we can all go home, right?

Fat chance. If that was all there is to this, I wouldn’t have much of a blog post, would I? The problem with that answer to our question is that for many people, such an answer appears to be nothing more than a murky vat of theoretical mumbo-jumbo. Nothing has really been contributed to the conversation about filesystem permissions until we can take that answer and break down how to apply it to the practical, every day task of deploying and/or securing your PHP web application.

So the secondary, and more practical, question which is posed becomes:

How do I determine the minimum amount of access required for my web application to function?

Rolling Up Our Sleeves

The flagship issue which needs to be tackled on this topic is understanding which system users will need the ability to perform what operations on your application’s filesystem resources. An application agnostic explanation of these needs is as follows:

  • The script user and group: This is the user and group your PHP scripts are executed as. This user will require READ and WRITE access to all of your application’s files, and will require READ, WRITE, and EXECUTE access to all of your application’s directories.
  • The web server user and group: This is the user and group which the web server process is executed as. This user will require READ access to all of your application’s files which are not scripts. This user will require READ and EXECUTE access to all of your application’s directories.

As a note on staying true to our principle, if you have access to more detailed information specific to your application’s architecture, it is possible to make more restrictive determinations about your application’s minimum need. For example, in the days before it had an automatic updater, WordPress would have been fully functional with its scripts having write access to only 3 directories: wp-content/plugins, wp-content/themes, and wp-content/uploads. Before the age of automatic updates, the script user could have been granted read-only access to all other files and directories. While the example is no longer relevant, as WordPress now utilizes an automatic updater (and the security gain from having auto updates far outweighs the security gain of having read-only files), it gives you an idea of how having some application specific knowledge can be used to further restrict access to your files in observance of the principle of least privilege.

Into the Environment: Discovering Our Users

To model what level of privilege is required by which users is a critical first step in determining what modes to set on which files and directories. However, unless we can correctly determine which system user in the production environment corresponds to which user within our model, the exercise is purposeless.

This is where many people go wrong with setting their filesystem permissions. They struggle to determine which user their scripts are actually executing as, and in their Flailing Fits of Futility™, resort to the bedeviled 666 mode, or the worse yet 777 mode.

It is not so difficult to empathize with these people. Determining the user and group which your scripts are executing as is not always straight forward, and is dependent on the details of the PHP handler being utilized in your hosting environment. In the section below, we cover common PHP handlers, and how each of them affect ownership semantics.

Determining the Script User: A Shallow Look at PHP Handlers

We will address three of the most common handlers here:

Apache’s PHP module (mod_php)

This handler is exceedingly popular in the web hosting market, in part due to its ease of configuration, and in part due to certain performance benefits it can offer over alternatives like suPHP.

The important thing to understand in the scope of our conversation is that Apache’s PHP module will execute all PHP scripts as the same user which the web server itself is executing as. On many systems, this is the www-data or www user.

suPHP

The suPHP handler will spawn a new PHP interpreter for each script which needs to be executed, and this new interpreter will assume the user and group of the owner of the script being executed. For example, if the following script were executed using the suPHP handler:

1
2
3
$ ls -l /srv/http/james/public_html/
total 0
-rw-r--r-- 1 james users 0 Sep  1 21:15 index.php

The script index.php would execute as the user james and group users, because james and users are set as the owning user and group respectively.

This behavior makes suPHP a popular choice in shared hosting environments, where each application can have its own user with which to execute its own scripts.

PHP-FPM

The PHP-FPM handler is a separate process from the web server entirely. This makes it the only handler on this list which can be used with alternative web servers, such as nginx, lighttpd, or whatever fancy thing the kids like to run these days.

Unlike the previous two handlers, there is no determinate pattern to which user a PHP-FPM process may be running as. Each process can be configured to run as any user on the server (this is a slightly oversimplified explanation, but that does not matter for our purposes).

In a well configured environment, a PHP-FPM process will be executed as the same user and group as owns all of the application’s filesystem resources. Any further discussion of this handler will assume it is being used in a well configured environment, but you should not assume that your environment is well configured! Make sure to check with your server administrator about this, or verify your configuration if you are the server administrator.

You can always ask

While this knowledge is valuable for anyone who is attempting to learn how to manage their own environment, if your web host or administrator takes care of all these prickly details for you, the best thing to do is simply ask what user your site’s PHP scripts will execute as.

Determining the Web Server User

The web server user is far more straight forward to determine. On the majority of systems, the web server process will simply be running as a user named www-data or www. If you are unsure, remember you can always use the ps command to double check.

1
2
$ ps axo pid,user,group,command | grep '[a]pache'
26453 www-data www-data /usr/sbin/apache2 -k start

Once again, if all these details are handled by your administrator or web host, the simplest thing to do is just ask which user the web server is running as.

The Final Step: Setting Your Modes

Now that we have determined which user the web server executes as, which user our scripts will execute as, and which of those users needs what level of access to which resources, there is one final determination to be made: What user and group own the resources which we are providing access to?

This should be simple to determine. To view an example of how this can be done from the command line, revisit the “Building on the Basics” section. If you need help determining this, consult your friendly neighborhood system administrator.

Once we know all of this information, we are prepared to begin setting filesystem modes. Rewinding back to our discussion about which users will require what level of access to which resources, we essentially (albeit quite subtly) broke down the application’s filesystem resources into three different control groups:

  1. Non-script files (CSS, javascript files, images, etc)
  2. Script files (PHP scripts, any files with embedded PHP code)
  3. Directories

We can determine the mode to be set for all of the resources in each of these control groups by asking ourselves four questions in each case:

  1. Is the script user the same user which owns this resource?
  2. Is the script group the same group which owns this resource?
  3. Is the web server user the same user which owns this resource?
  4. Is the web server group the same group which owns this resource?

Once each of these questions is answered, we know what the minimum mode is which each resource can be set to. We can illustrate the minimum modes in a simple matrix for each control group.

Non-Script Files

Recalling that the web server user will require READ access to these files, and the script user will require READ and WRITE access to these files, we can refer to the following matrix to determine what modes these files should be set to.

Script Files

Recalling that the web server user does not need access to these files, and the script user needs READ and WRITE access to these files, the following matrix will guide us in setting modes on scripts.

Directories

Recalling that the web server user will require READ and EXECUTE access to directories, and the script user will require READ, WRITE, and EXECUTE access, the final matrix will provide guidance in setting the appropriate modes on directories.

Digesting the Matrices

If you took some time to look over each matrix in its entirety, you have undoubtedly noticed that each one bears a column which would require us to set permissions to one of our forbidden modes (666 or 777). These modes become mandatory for your application to function in any environment in which PHP scripts are not executed with either the same user or the same group as the owner of your application’s filesystem resources.

If you are a web host, and your environment imposes that condition, you need to either immediately atone for your sins and fix your environments, or do the honest thing and dismiss yourself from the industry.

If you are a website administrator and your web host’s environment imposes that condition, fire them immediately. Your website is not safe with that provider.

There is however another, less obvious, permissions mode which we see recur in the matrices which, in certain environments, carries some grave security risks of its own. That is, any permissions mode which grants group write capabilities (660, 664, 770, 774, etc). These modes are imposed by any environment in which PHP scripts execute as a different user from the owner of the filesystem resources, while executing as the same group of the resource owner. This is a condition commonly imposed by environments running mod_php, in which scripts are executed as the same user which the web server is executed as.

The danger of this condition applies specifically to shared environments in which multiple sites must share the same group as the executing PHP handler (this is how basically any shared mod_php environment will be configured). If each site’s resources require group write permissions to be set, and each site is a member of the group which the PHP handler is executing as, then every such site will have full write access to the resources of every other site using the same PHP handler. Consequently, if one site suffers a compromise, malware can freely spread to the other sites without any need to find or exploit vulnerabilities in those sites. This is not a far fetched, theoretical scenario. This happens in real life.

So if you are a web host or an administrator, the meaning of it all boils down to this: Do not configure mod_php in your shared environments. You are endangering your customers or your sites by doing so. Stick to utilizing either suPHP or PHP-FPM in these environments.

If you are a website administrator, what this means for you is you should not place your site in a shared hosting environment which is running mod_php. Ensure the environment runs a PHP handler which will allow scripts to execute as the same user and group which own your application’s filesystem resources, such as suPHP or PHP-FPM. If your current host does not offer such a shared environment, either purchase a dedicated environment from them (dedicated server or a VPS), or fire them and find a web host that offers secure shared hosting.

Final Thoughts

Understanding the meaning of a permissions mode is simple. You can look at the number “640” and easily break down what each digit means. However, understanding the meaning of the digits is a tiny, tiny first step on the right path. This understanding only carries value if you also understand when to apply which modes, and to which resources they must be applied. As we saw through our exploration of the question “How do I decide what modes to apply to which filesystem resources?”, the answer is not a cut and dry explanation. It is a process which requires understanding details about your environment and your application, and requires leveraging these details to provide the minimum possible level of access to your files and directories.

It is not enough to simply determine the minimum level of access to your resources which is required by your application. Observing good filesystem security would impel us to take one step further and pose the question, “Is this minimum level of access restrictive enough?” If it is not, then the right thing to do is either configure the environment to allow the setting of modes which are restrictive enough, or migrate to an environment which is already configured that way.

These basic principles of web application security are all too often overlooked. Whether it is simply from lack of knowledge, or worse yet, from willful neglect, too many production environments end up vulnerable to compromises which require no exploitation of application level vulnerabilities.

So take the information in this blog post. Share it. Re-post it. Plagiarise it. Credit it. Don’t credit it. I don’t care. Just be a participant in spreading good information so that a few more websites out there can be a little more secure, and hopefully save guys like me some very grinding, tiresome, and unpleasant days in the office.

Comments