This boys and girls is why you don't put a config file full of passwords into a web accessable directory
OMG!! An actual POST. (more on that later)
So I'm playing with StumbleUpon earlier and I hit the button and suddenly a strange page. Full of code. To my surprise its actually their code ... more specifically it seems to be a configuration file for databases, and network topology and it includes the passwords.
(and to answer everyone's question: I didn't use the information for evil, nor is the information available to anyone for evil or otherwise. As much as I wanted to keep it for posterity, I deleted it. No chance of someone using my computer and finding it, or my own temptations getting the better of me).
A combination of PHP, inexperienced developers as well as the rise of cheap shared hosting have made this a wide-spread problem, not just for StumbleUpon. One thing I really like about Perl is the "use strict" pragma, which forces you to say "my included file is right here in this directory" ... otherwise it looks only in a specified path.
PHP includes files in a specified path as well, but it includes "." at the beginning by default. If your app relies on a file being in the include path and someone managed to put a file with the same name in the same directory as the script, they can effectively run whatever code they want. The second problem is what happened today. If someone forgets or corrupts the <?php tag then the server happily outputs the code for you.
Many people don't realize they can put files in a folder other than the web accessable folder and it still be accessable with PHP. Though there are some hosts that don't allow you to access these folders (usually the web accessable folder is public_html, html, or www ... most people have hosts that allow access to the parent directory when you log-in)
If your host only allows access to the web enabled folder:
If your shared host only allows you to save to the web accessable folder. The best advice I can give is "change hosts". I own one, and I don't do that to you ;-)
Barring that you can create a file in the folder and call it .htaccess (note the leading "."). In this file put the following lines:
<LocationMatch .*config\.php.*>
Order Deny, Allow
Deny from all
</LocationMatch>
(change config.php to whatever your config file is called)
Now some hosts won't let you have directives like this in .htaccess, you can put some code in the top of the config file to check for unauthorized access but that won't save you from mistyping the <php tag. Really the best option is to avoid these hosts.
Moving configs to a non-accessable directory
The web server looks in a particular directory (usually "public_html", "html" or "www") for files to serve up to a browser. Any files outside that directory cannot be accessed. By far the safest option is to always put your configuration files, ESPECIALLY ones containing passwords, outside the directories the web server can see. PHP on the other hand can see files anywhere on the server's filesystem as long as it has permission to do so. Some things you can do, or not do to make this as secure as possible:
Don't rely on the include path unless you set it yourself with "set_include_path()"
Don't use ".." to access the parent directory. Use the full path, or set the full path. If you aren't certain what your full path should be create a small php file with the following (put it in your main web directory:
<?php
print getcwd();
?>
When you run it in your browser you should get something like /home/foo/public_html ... ("foo" is usually your username, and public_html is usually the web-folder). The part before the name of your web folder is the absolute path for your files on the system. So if you have:
include "/home/foo/config.php";
That includes a file called "config.php" that is in the parent folder of your web site and is not web accessable.
Make sure the file is not writable by anyone other than yourself. (in FTP or if you have shell access you can do:
chmod 644 config.php in the directory its located in)
And really this should go for any included files that you'd rather not have the code show up. Put your code in modules and call it. If code in the main directory gets exposed its much better to just show the file your including rather than actual code that could possibly be used to exploit your server with.
Getting existing apps to work after moving their config files
Since many people use open source apps, and lots of open source apps keep these files in web directories its a good idea to modify them to look for their files elsewhere. Most of them have a file that everything else accesses (such as config.php or init.php or something similar). Sometimes they will have multiple config files that point back to the common one in the main folder. This is still acceptable. Sometimes the file resides in another folder such as includes/ ... if this is the case you will probably need to move the entire folder (either that or you'll have to modify the code itself to point to the new location).
I recommending putting everything you move into its own folder. For instance say your host has you setup in /home/foo . Your web directory is "public_html" and your app has a folder called "includes" currently in "public_html"
Inside the includes folder is a file called "config.php" every other script in the app accesses this file.
create a folder called "myapp" and put it in /home/foo (mkdir myapp)
move the app's includes folder into your new folder and out of public_html
So in the end you'd have:
/home/foo
/public_html
/includes
/myapp
/includes
Back in the public_html create a new folder called "includes" and create a new file also named "config.php" and put it in it.
In this config.php put the following code:
<?php
$path = explode(":", get_include_path() );
$keyed_path = array_flip($path);
unset($keyed_path['.']);
$path = implode(":", array_keys($keyed_path) );
set_include_path( "/home/foo:$path" );
?>
You'll need to make sure the app doesn't set the path in its initial config for this to work. If the app doesn't work, check that it doesn't use parent directories ".." in paths (its okay for the config file call but subsequent calls will break in this scenerio)
Questions and comments welcome!
Update BTW Blogger is horrible at not encoding entities such as < and ate much of my original post. I'll do a rant on that soon :)
update 2 fixed more code that blogger ate that I didn't notice
update 3 All code contained in this post is public domain. I make no guarantees that it will work or that it won't blow your app up. I cannot be responsible for its use.
So I'm playing with StumbleUpon earlier and I hit the button and suddenly a strange page. Full of code. To my surprise its actually their code ... more specifically it seems to be a configuration file for databases, and network topology and it includes the passwords.
(and to answer everyone's question: I didn't use the information for evil, nor is the information available to anyone for evil or otherwise. As much as I wanted to keep it for posterity, I deleted it. No chance of someone using my computer and finding it, or my own temptations getting the better of me).
A combination of PHP, inexperienced developers as well as the rise of cheap shared hosting have made this a wide-spread problem, not just for StumbleUpon. One thing I really like about Perl is the "use strict" pragma, which forces you to say "my included file is right here in this directory" ... otherwise it looks only in a specified path.
PHP includes files in a specified path as well, but it includes "." at the beginning by default. If your app relies on a file being in the include path and someone managed to put a file with the same name in the same directory as the script, they can effectively run whatever code they want. The second problem is what happened today. If someone forgets or corrupts the <?php tag then the server happily outputs the code for you.
Many people don't realize they can put files in a folder other than the web accessable folder and it still be accessable with PHP. Though there are some hosts that don't allow you to access these folders (usually the web accessable folder is public_html, html, or www ... most people have hosts that allow access to the parent directory when you log-in)
If your host only allows access to the web enabled folder:
If your shared host only allows you to save to the web accessable folder. The best advice I can give is "change hosts". I own one, and I don't do that to you ;-)
Barring that you can create a file in the folder and call it .htaccess (note the leading "."). In this file put the following lines:
<LocationMatch .*config\.php.*>
Order Deny, Allow
Deny from all
</LocationMatch>
(change config.php to whatever your config file is called)
Now some hosts won't let you have directives like this in .htaccess, you can put some code in the top of the config file to check for unauthorized access but that won't save you from mistyping the <php tag. Really the best option is to avoid these hosts.
Moving configs to a non-accessable directory
The web server looks in a particular directory (usually "public_html", "html" or "www") for files to serve up to a browser. Any files outside that directory cannot be accessed. By far the safest option is to always put your configuration files, ESPECIALLY ones containing passwords, outside the directories the web server can see. PHP on the other hand can see files anywhere on the server's filesystem as long as it has permission to do so. Some things you can do, or not do to make this as secure as possible:
Don't rely on the include path unless you set it yourself with "set_include_path()"
Don't use ".." to access the parent directory. Use the full path, or set the full path. If you aren't certain what your full path should be create a small php file with the following (put it in your main web directory:
<?php
print getcwd();
?>
When you run it in your browser you should get something like /home/foo/public_html ... ("foo" is usually your username, and public_html is usually the web-folder). The part before the name of your web folder is the absolute path for your files on the system. So if you have:
include "/home/foo/config.php";
That includes a file called "config.php" that is in the parent folder of your web site and is not web accessable.
Make sure the file is not writable by anyone other than yourself. (in FTP or if you have shell access you can do:
chmod 644 config.php in the directory its located in)
And really this should go for any included files that you'd rather not have the code show up. Put your code in modules and call it. If code in the main directory gets exposed its much better to just show the file your including rather than actual code that could possibly be used to exploit your server with.
Getting existing apps to work after moving their config files
Since many people use open source apps, and lots of open source apps keep these files in web directories its a good idea to modify them to look for their files elsewhere. Most of them have a file that everything else accesses (such as config.php or init.php or something similar). Sometimes they will have multiple config files that point back to the common one in the main folder. This is still acceptable. Sometimes the file resides in another folder such as includes/ ... if this is the case you will probably need to move the entire folder (either that or you'll have to modify the code itself to point to the new location).
I recommending putting everything you move into its own folder. For instance say your host has you setup in /home/foo . Your web directory is "public_html" and your app has a folder called "includes" currently in "public_html"
Inside the includes folder is a file called "config.php" every other script in the app accesses this file.
create a folder called "myapp" and put it in /home/foo (mkdir myapp)
move the app's includes folder into your new folder and out of public_html
So in the end you'd have:
/home/foo
/public_html
/includes
/myapp
/includes
Back in the public_html create a new folder called "includes" and create a new file also named "config.php" and put it in it.
In this config.php put the following code:
<?php
$path = explode(":", get_include_path() );
$keyed_path = array_flip($path);
unset($keyed_path['.']);
$path = implode(":", array_keys($keyed_path) );
set_include_path( "/home/foo:$path" );
?>
You'll need to make sure the app doesn't set the path in its initial config for this to work. If the app doesn't work, check that it doesn't use parent directories ".." in paths (its okay for the config file call but subsequent calls will break in this scenerio)
Questions and comments welcome!
Update BTW Blogger is horrible at not encoding entities such as < and ate much of my original post. I'll do a rant on that soon :)
update 2 fixed more code that blogger ate that I didn't notice
update 3 All code contained in this post is public domain. I make no guarantees that it will work or that it won't blow your app up. I cannot be responsible for its use.
Comments