With WordPress more popular than ever, boutique hosts are popping up everywhere offering the promise of “bulletproof” hosting. For those that don’t have the resources to administer a VPS, a managed environment tuned for performance, security, and reliability seems worth paying the extra expense. After vetting three of these services for a project, my advice is “Be careful.” Not all services are created equal.
The Problem
Shared PHP hosting requires a careful system admin. In a typical mod_php Apache httpd installation, all virtual hosts share the same Apache instance running with the same permissions. Unless special precautions have been taken, any PHP file can read/write/execute any file that the Apache process has permission to read/write/execute. Deploying in this situation means that you must trust all of your neighbors.
Over the last week, I tested three managed WordPress hosts. How did they fare? Not, good. Two hosts with a good reputation in the community have serious vulnerabilities. The vulnerabilities are severe enough that I could easily manipulate the data of an adjacent installation.
How do you know if your host is vulnerable?
Below is a script borrowed from phpsec.org:
<?php echo "<h3>Current directory:" . dirname(__FILE__) . "</h3>\n"; echo "<pre>\n"; if (ini_get('safe_mode')) { echo "[safe_mode enabled]\n\n"; } else { echo "[safe_mode disabled]\n\n"; } if (isset($_GET['dir'])) { echo "<h4>Scanning: " . htmlentities($_GET['dir']) . " </h4>\n"; ls($_GET['dir']); } elseif (isset($_GET['file'])) { cat($_GET['file']); } else { echo "<h4>Scanning: / </h4>\n"; ls('/'); } echo "</pre>\n"; function ls($dir) { $handle = dir($dir); while ($filename = $handle->read()) { $size = filesize("$dir$filename"); if (is_dir("$dir$filename")) { if (is_readable("$dir$filename")) { $line = str_pad($size, 15); $line .= "<a href=\"{$_SERVER['PHP_SELF']}?dir=$dir$filename/\">$filename/</a>"; if(is_writable("$dir$filename")) { $line .= " (writable)"; } } else { $line = str_pad($size, 15); $line .= "$filename/"; } } else { if (is_readable("$dir$filename")) { $line = str_pad($size, 15); $line .= "<a href=\"{$_SERVER['PHP_SELF']}?file=$dir$filename\">$filename</a>"; if(is_writable("$dir$filename")) { $line .= " (writable)"; } } else { $line = str_pad($size, 15); $line .= $filename; } } echo "$line\n"; } $handle->close(); } function cat($file) { ob_start(); readfile($file); $contents = ob_get_contents(); ob_clean(); echo htmlentities($contents); return true; } ?>
- Copy the code to your favorite editor, save as dir-scan.php, and upload to the root of your web directory.
- Visit the page by going to http://hostname.com/dir-scan.php
- When the page loads, you will see the current directory, whether safe_mode is active, and listing of the files/directories in “/”. If no files are listed that is good.
- To view a specific directory, go to http://hostname.com/dir-scan.php?dir=/var/www/path.
You don’t seem to be advocating one way or the other, but it’s worth noting that safe_mode is deprecated in PHP 5.3. Even in builds of PHP that still include it, it’s not a productive way to secure a hosting environment. Many of the best shared hosts use PHP with with the CGI/FCGI SAPI in order to have more fine-grained control over the security issues you’re discussing here. Mod_php is excellent software but is not appropriate in all situations.
Thanks, Josh. I should have provided the details of each host’s server configuration. One host was using FastCGI with Litespeed, but there was a configuration issue, which caused the vulnerability. The host that I found to be secure was using mpm-itk with all of the provisioning and system-level scripting done in ruby. And I don’t remember how the host that had system-level scripts executing right along side customer code was set up. Although I guess that doesn’t really matter because no setup can make that system design secure.
In all cases, I think a monitoring script that checks for known potential vulnerabilities is a prudent approach.