1% of CMS-Powered Sites Expose Their Database Passwords (2011)
feross.org
feross.org
1. Disable swap/backup files in your editor (or write them to a different location)[1]
2. Git ignore or SVN ignore swap files and backup files
3. Configure your web server to not serve such files.
Some combination of these should keep you safe. :)
[1]: in vim: noswap nobackup nowritebackup or http://vim.wikia.com/wiki/Remove_swap_and_backup_files_from_...
And shared hosts don't generally allow files outside the webroot of a site. When they do, they might already have open_basedir set to only allow inclusion WITHIN the webroot.
Most packages like Wordpress are developed to run on the maximum number of servers. It isn't built to run on the best, or smartest configured ones—but the average, out-of-the-box Apache/PHP install.
Example: PHP 5.5 will be running for the next billion years because when mysql_query is finally put to rest in newer versions all those applications that depend on it will fall over. Thus, a legacy version of PHP will be supported by hosts, bugs, security holes and all.
"You either die a hero, or live long enough to see yourself become the villain..."
PHP crossed the line from hero long ago.
Everything was written below a public root, but the shared host didn't allow this, so the next thing you saw was: domain.com/publicroot/index.php^ when the new developer took over. The funniest thing was that they had internal subdomains which ended up public as well, one with full customer listings.
"Never attribute to malice that which is adequately explained by stupidity." - Hanlon's Razor
^ fake path
I bet you 1% of every web site or server in existence does something so blatantly and unthinkably wrong that it would make any sysadmins eyes pop out of his head.
1% is in fact extremely low in my opinion—my guess would be closer to 10-15% of sites have some glaring security hole.
The only important thing is to not let it be your site.
I wonder what the percentages are for cops, doctors, judges, and pilots are?
# prevent hidden files from being served and logged
location ~ /\. {
access_log off;
log_not_found off;
deny all;
}
# prevent tilde files from being served and logged
location ~ ~$ {
access_log off;
log_not_found off;
deny all;
}A much cleaner solution would be to separate "callable" entry-point files (like index.php) from "library" files into separate directories and point nginx/Apache only to the directory with callable files.
The .htaccess hacks are great but they are just patching the symptom, and one slip up and you're back to square one.
The best way to do configuration is to have it in environment variables that are populated in a completely separate config file for the specific instance, so for instance a uWSGI ini file.
This is very easy with Django and uWSGI.
In your uWSGI.ini:
env = DJANGO_SETTINGS_MODULE=yoursite.settings.production
env = DJANGO_SECRET_KEY=herp
env = DJANGO_DB_PASSWORD=derp
In yoursite/settings/production.py from .base import *
In yoursite/settings/base.py import os
DATABASES = {
'default': {
...
'PASSWORD': os.environ.get('DJANGO_DB_PASSWORD'),
...
}
}
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
I'm not sure if this is possible with WordPress or the whole shitty PHP way of doing things - perhaps if you had a FPM pool for each site and site specific configuration in there?You can do stuff like include /srv/*/pool.ini, right?
; To configure the pools it is recommended to have one .conf file per
; pool in the following directory:
include=/etc/php5/fpm/pool.d/*.conf
Then you could configure ENV inside FPM pool using the env directive: env[DB_HOST] = localhost
env[DB_USER] = foobar
env[DB_PASSWORD] = foobar
...and use something like this in e.g. Wordpress config: define('DB_NAME', getenv('DB_NAME'));
define('DB_USER', getenv('DB_USER'));
define('DB_PASSWORD', getenv('DB_PASSWORD'));
The biggest caveat is you MUST disable phpinfo() php_value[disable_functions] = phpinfo
Otherwise these ENV will shown up in any page that calls phpinfo();So, they are paying for it by people who are presumably more experienced.
Edit: Just to be clear, I'm not excusing any of the mistakes. Just pointing out how normal people could get screwed over, even if they are using a "professional service" and paying for it.
The best way to do configuration is to have it in
environment variables
Isn't it the only sensible way, actually?Django doesn't expose static files the same way, so you still get away with a secret.txt stored as a file.
Complete untrue. You can (and are advised to) move your wp-config.php above public_html. The reason its not done by default is because you just can't do this on many of the crappy hosting services, and it creates a barrier for entry for people making their first-ever site.
Do software like XAMP have bad defaults and shouldn't be used for production out of the box? Maybe.
Has that helped a lot of people to get started, and make PHP the most popular server language for the web? Definitely.
Should we mock all php devs including experts, because of designers or ninja CEOs who tried/succeeded in editiing or making a website but made some mistakes in the process? The answer is still no.
For example with a Symfony app:
. - App root
./web/ - httpd doc root
./app/ - app files
./app/config/ - config files
Barring an exploit that lets you break out of the httpd doc root (not saying this is impossible), there is no way to request the config or app files directly.
The issue however is if you have a copy of said file, in which case protecting the main version would be useless.
Also I'd say the blame if you can assign any is on Vim, Emacs, Gedit, and Nano which would have had to crash in order to set these chain of events in motion.
Take away is to not use an editor that auto-saves or to save it on your local computer and put the finished file onto the server.
... Or the guy who is just editing files directly on the server (or shovelling everything up with FTP), instead of sane version control.
(I'm not sure anyone doing the former can be counted as "Pro", WP or otherwise.)
(A) Database passwords are a security risk. You don't want them escaping to other servers when you clone or share code.
(B) Wordpress is commodity software. You are unlikely to need custom modifications to the source. "I'm on version 3.4.2" is sane enough version control.
(C) Database passwords are ephemeral. You don't need to keep a durable record of them. If your hard drive fails or you otherwise lose your record of them, you can just change the password. What is needed is a good backup strategy, not a durable password.
I would say live editing wp-config.php outside of version control is the best strategy, until you start needing to synchronize multiple webservers. At that point you should switch to some deployment and configuration manager like Chef or Puppet, not put passwords into version control.
(It seems I skipped actually writing something useful and went straight to durr version control, sorry.)
Points A) and C) are dead on. Addressing your point B), though:
Yes, it is commodity software. But most seem to use at least some plugins and themes, and making changes to those without a rollback is a nightmare. You can make backups before changing things, sure, but version control has that already built in.
(Sibling posts to yours point out that Wordpress looks in both the docroot and one level up for wp-config.php - if I ever manage a Wordpress site again I'll be sure to move it out.)
Which if allowed is even more stupid.
If you run mysql only locally then do skip-networking and if you have to have networking restrict the ips it's allowed from.
If they can use the mysql password locally, well then you have far bigger problems with security than mysql and exposed php configuration files.
Some things never change.
You can store the login credentials there : http://www.php.net/manual/en/pdo.construct.php
This is another reason why you should move away from mysql(i) to PDO.
Or if that doesn't work, try storing in the .htaccess or Apache conf environment variables : http://stackoverflow.com/a/2583857
http://codex.wordpress.org/Editing_wp-config.php#Configure_D... http://codex.wordpress.org/Hardening_WordPress#Securing_wp-c...
I think the chance of successfully obtaining DB credentials using this method is fairly high even without those "backup files" mentioned in the link.
I'd assume there are many people out there who can set up a simple CMS themself but ignore/don't understand how to properly remove the various "installer" and "configurator" scripts once they're done...
"If the text editor crashes or the SSH connection drops during editing"
What about the time of editing? During that time, the temp files exist. Are they readably? I would guess so. So even if you just edit them and have to crash, you are vurnurable.It's standard practice for most web frameworks, and yet it seems the most popular CMSs don't bother.
http://ycorpblog.com/wp-config-sample.php
http://blogs.wsj.com/law/wp-config-sample.php
http://blog.us.playstation.com/wp-config-sample.php
...
> Latest stats say that about 13.8% of the top 10,000 websites run CMSs. If we just focus on CMS-powered websites, then the percentage of vulnerable sites is much higher:
> Thus, 230 / (216391 * 0.138) = 0.77% of websites running a CMS are vulnerable.
I don't think those numbers mean what you think they mean.
13.8% out of 10,000 doesn't say much about the top 216,391. And perhaps 0 out of 230 of the vulnerable websites use CMS, however unlikely that is.
RewriteCond %{REQUEST_URI} ^somefolder.*
RewriteRule ^(.*)$ /index.php?/$1 [L]found this in comment, it's useful to me
Assuming one follows the "defense-in-depth" approach, however, this is easily mitigated and becomes a non-issue.
FWIW, I could give you the username and password that my instances of WordPress use to connect to MySQL and you wouldn't be able to do anything with them.
I have never thought about this, as I'm super paranoid about database credentials stored in any sort of config file (where it's wp-config.php, settings.php or any other language with frontfacing credentials).
Great writeup ferross!
find . -name "*.swp"
You can find and remove them with: find . -name "*.swp" -exec rm -f \{\} \;find . -name "*.swp" | xargs rm
I believe find -exec forks and execs once for every file found, xargs may only fork and exec once, provided that all of the files find finds fit in a single command line. Hopefully not an issue in this case, but it can greatly speed up a deletion when you have a lot of files to find and delete.
[EDIT] Doesn't properly handle spaces in filenames, see the comments below for other slick solutions.
You need to add -print0 to find, and -0 to xargs to make it work properly: find . -name "*.swp" -print0 | xargs -0 rm
But better would be to use -delete as I wrote above.
I dont know how useful it is for passwords but very useful for email spamming!
<Files ~ "(^#.*#|~|\.sw[op])$"> Order allow,deny Deny from all </Files>
What would be the equivalent of this for Nginx?
location ~ "(^#.*#|~|\.sw[op])$" {
return 401;
}
Or something along those lines.Nodesocket's answer is good as well: http://news.ycombinator.com/item?id=5164017
Simply giving the hacker less information (though not just depending on this) is a useful form of security. If you give them a 401, then they at least know that the file exists.
Also you can move wp-config.php outside the root.
does the DB password mean anything without allowing remote connections ? (let's forget shared hosts for a moment)
But...
It is rare there is only one app on a server, even a non-shared one, so this information could be used in conjunction with this information in order to cause bother. It is not uncommon to see something like phpMyAdmin installed in a standard location on a given domain and not locked down well - for sites where this is the case this bug is very serious.
It is scary how many people out there calling themselves sysadmins use the same password for everything to do with a given service, or even for everything - for them this is a bigger problem as revealing the DB password also reveals the credentials needed to access other things (perhaps an SSH account with privileged access either directly or via sudo).
That should immediately mark them as a Dunning-Krueger victim/hack and you should get someone else. If you're not using something equivalent to a password vault or something equivalent, you're not as security savvy as you think you are.
That depends on the contents of the file in question. Example: An attacker can forge hmacs if the config file contains the signing key.