Where do I store my database credentials?
There comes a point, in security matters, when developers run into the age-old question: “Who was first? The chicken or the egg? Or the hen? Perhaps the fowl?”
You (your scripts) need an user name and password to access the database server. Where to securely store these? Yes, in a database table! What an elegant, secure solution! Oh, wait… You need an user name and password to access the database server in order to retrieve the user name and password required to access the database server.
Use a “vault” directory
At this sad point it becomes clear that you either develop an extremely complex mechanism involving cascading several databases for various purposes (such as storing credentials and encryption keys and settings), and keep some entry-level credentials on the file system, or on another server or something (such as some high-value systems), or you save your credentials on the file system directly, protected by a properly set up “system” directory, and some extra other measures:
- during system installation (whether automated or manual), create a “vault” directory inside the “system” directory, with a random name, which will not be revealed to anyone, not even to system administrators, after installation completes. The only way to find this directory is to navigate the website file system via FTP.
- place database access credentials (and other sensitive data, such as encryption key) into the “vault” directory, inside PHP files, as PHP variables, both for use readily, and for avoiding direct output to browsers should all protection mechanisms fail this far. To obtain the credentials in any of your scripts, simply require these scripts.
- create an .htaccess file to deny all access from the web to the “vault” directory and to disallow indexing; make all files inside and the directory itself read-only, and only readable by owner (CHMOD to 500) (see securing your web server).
- put absolutely nothing else in here, and plan never to.
- now make the “system” directory itself read-only.
(From this point on, your system data is cocooned in an unknown – and unguessable – place on your file system, with limited and well controlled web access, in a read-only environment, limited to file owner.)
Now, why not put these files directly inside the “system” directory, it seems pretty secure, doesn’t it? Yes, but it still allows for some web access, and denying web access for individual files adds unwanted complication (remember to KISS). Using the “vault” directory technique allows for a more hermetic storage of this sensitive data.
Accessing the vault directory
Impossible from the web, thanks to our setup. But how to access it (and files inside it) if it has a random name, that isn’t saved anywhere (well, except on the file system records)? Remember that the “system” directory name at least has a corresponding hard coded configuration variable. But the “vault”?
The easy (KISS) way: make sure the “vault” directory is the only directory in the “system” directory (or, if you wish or need, create another directory, with a known name, inside the “system” directory, and place the “vault” directory in there, again ensuring that it is the only directory inside the parent directory). Create a function, say get_vault_dirname(), which scans the parent directory (whose name is known to the script), and returns the name of the first (and only) directory it finds inside: that is your “vault” directory.
Your “system” directory is: site_root/sys_dir_name_saved_in_a_config_var/
“Vault” directory could be: site_root/sys_dir_name_saved_in_a_config_var/whatever_constant/vault_dir_name/
By scanning site_root/sys_dir_name_saved_in_a_config_var/whatever_constant/ for directories, the first and only one found will be the vault directory.
Does this incur a (tiny) performance penalty? Probably. Is it worth it? Definitely. This makes sure an attacker can find your “vault” directory only by doing the same (after he/she has planted a malicious script on your server, in which case it’s “game over” anyway and regardless), or by breaking into your FTP server, thus being able to just navigate to it.
Firstly, an attacker would have to go through all the trouble with the “system” directory. Assuming he gained access to your administrative interface, he still has no idea what the “vault” directory’s real name is, and where to look for the files containing your credentials. Therefore, the attacker can still only access the database via the website (cannot connect directly to it). In terms of encryption, even if the same hacker stole some encrypted database, he still won’t have the encryption key, stored in the “vault” directory, which he can only find by breaking into your FTP server also…
Therefore, with this approach, to completely and utterly defeat your system, an attacker is indeed required to break all the security layers, which complies with the principle of security being directly proportional with the amount of work a wrong doer must exert to bypass it.
Pretty secure, I’d say.