PHP Filesystem Security
While server security is often considered to be beyond the purview of web application developers, there is ample opportunity for developers to take preventative measure to help ensure the security of their systems. While much of PHP security concerns itself with securing the application or data layer from abuse, the security of the files that make up the application itself is often given short shrift. Often the most dangerous threat to any application is an insider threat. When considering PHP application security it is important to consider not just a malicious web user, but also a malicious user on the filesystem. Without proper protection the PHP files themselves can expose data or be tampered with by filesystem users.
Short Overview of Permissions
It is extremely important to understand how filesystem permissions work and their proper utilization. Often times web developers are constructing applications on a different platform or environment than the production machine. Code is developed in one location and deployed in another. It is important to check the file permissions on the deployment system to ensure that proper preventative measure are being taken.
There are other articles on this site discussing file system permissions so please refer to them for a more detailed discussion (links below). A brief overview will help discussion however. Linux file permissions are presented as a series of 10 characters that represent the permissions for files in a directory. Using the '-l' operator with the 'ls' command will show the file permissions of the specified (or current working) directory:
justin@madirish $ ls -l -rw-rw-r-- 1 justin users 557 Jan 11 11:21 some_list.txt drwxrwxr-x 7 justin users 4096 Jun 13 2006 public_html
In the above example you can see the permissions listing. The first letter will be set to -,d, or l. A dash indicates a file, a 'd' indicates the listing is a directory, and an 'l' indicates that the listing is a link. The next nine letters can be divided into three groups. The first three letters indicate user permissions, the next three indicate group permissions, and the last three indicate 'other' permissions (permissions for any account that does not fall into the user or group). The letters listed here (in order) are 'r' for read, 'w' for write, and 'x','s', or 'T'. The 's' stands for setuid or setgid (depending on whether it is in the user or group permissions) and the 'T' stands for the sticky bit. Directories with the sticky bit set are special in that only the directory owner and root can delete files from the directory. Setting the suid and sgid on directories is also useful since new files in the directory will be created with the directories user and group permissions. This can be helpful in enforcing a default permissions set.
Critical Data Overwrite
The first threat to filesystem data in a PHP application is that critical data is overwritten. This means that the PHP or other files associated with your application are changed in some way. This can cause unusual behavior, lead to application compromise, or simply result in a denial of service condition.
Technically speaking, all the files in your application should only be writable by developers, and possibly the web server (depending on their usage). Once deployed the static files in your application should probably all be changed to remove the write permissions. This makes the files unalterable, which ensure that they aren't accidentally changed. Of course, this makes updates one step more complex since write permissions must be added, but for many applications files hardly ever change. Certain files such as logs, or upload directories will need to be writable, but be sure to restrict the write permissions to the web server.
You can easily revoke all write permissions from the top level application directory using:
chmod -R -w *
This 'chmod' is used to change file permissions, the '-R' flag is for recursive (so the changes will cascade) and the '-w' flag indicates to remove write permissions.
The next threat to your PHP application on the filesystem is that application data is leaked to unauthorized filesystem users. Remember that directories with the 'x' (execute) permission can be read or listed by the user, group, or other applicable. Note, however, that just because a user can't list the contents of a directory does not specifically mean they can't read the actual contents if the file or directory the user has sufficient privileges to read the target file or directory. For instance, if the directory /test contains the following files:
justin@madirish $ ls -l -rw-rw-r-- 1 justin users 557 Jan 11 11:21 some_list.txt drwxrwxr-x 7 justin users 4096 Jun 13 2006 public_html -rw-rw-rw- 1 justin mary 448 Feb 12 12:21 foo.txt
Even if the user mary doesn't have 'x' permissions on the directory test she can still read and write the file foo.txt (the trick is finding it). In fact, locating files across the filesystem isn't all that difficult for users. Using the 'locate' command a user could crawl the entire filesystem looking for files that they might be able to see:
justin@madirish $ locate db.php /var/www/html/dev/lib/db.php /var/www/sdata/devel/degree/lib/shadow_db.php
As you can see my user account may not have had permissions to list the contents of the directories containing the above files, but the locate command found them for me.
Ideally you should restrict all permissions to the user account of the web server and the group account of your developers. You should revoke all privileges to the 'other' accounts since they're unnecessary. The reason for this is you don't want other users to be able to look at your files as they could contain sensitive information:
justin@madirish $ ls -lah /var/www/html/dev/lib/db.php -rw-rw-r-- 1 apache dev 6.0K Apr 24 2005 /var/www/html/dev/lib/db.php justin@madirish $ cat /var/www/html/dev/lib/db.php [snip] $media = mysql_connect ("localhost", "admin", "adminpass") or die("Could not connect"); [/snip]
Because the others have read permissions on this file I was able to list the contents, and uncover a MySQL account and password that I could use to access the database.
Data Leakage to the Web
In the worst case scenario of data leakage your configuration information that includes usernames and passwords is displayed over HTTP to the web. This situation can be avoided in a number of ways. The easiest way to prevent this from happening is to encase your configuration information in interpreted PHP files. To do this you use a PHP file and assign account information to PHP variables. For instance:
<?php $username = 'foo'; $password = 'bar'; ?>
In the above file, even if it is called directly the information is protected since the web server won't render the variables into HTML that would be visible.
If you use .ini files or other formats be sure to use .htaccess files to protect access to them. The best way to do this is to place the configuration files in a directory and prevent web access to those directories using the following syntax in your .htaccess file:
Order deny,allow Deny from all
This way even if the configuration files are called directly they will not be rendered. Be sure to check your .htaccess files to make sure they are working! Correctly configured Apache (or other web server) directives are required for the proper operation of .htaccess files. Don't assume that simply because your .htaccess file is correct that it will work.
World Writable Files/Directories
The worst case exposure for you application files and directories is to have some material world writable. This means that anyone on the file system - users or processes, could overwrite your application data.
Finding world writable files is quite easy, using the find command:
justin@madirish $ find / -xdev -perm +o=w ! \( -type d -perm +o=t \) ! -type l -print
Any world writable file or directory is problematic. Even if you don't care about the contents of a file or directory you never want to provide an easy place for an attacker to write data. In addition to possibly being able to deface your site or implement a XSS attack, an attacker could dump data into a legitimate file to hide it from detection. All in all, having world writable files weakens the overall security of the host server.
Often times developers don't give much consideration to the filesystem upon which their applications are hosted. This attitude can cause serious problems to the filesystem and weaken the overall security stance of the hosting server. It is important for developers to understands the threats to filesystem security and take an active role in securing their own applications rather than leaving that task to overworked sysadmins. Ever developer needs to do their part to help insure the overall security of the system.