38

It's always bothered me that many PHP programs require the user to store the mysql password in plain text (in a string or constant) in a configuration file in the application's root.

Is there any better approach to this after all these years?

So far I have come up with two minimal security boosts:

  1. make the file unreadable via the web using rules in .htaccess (in case php fails or there's a security vulnerability to read php source)

  2. destroy the password in memory after the db connect is made (unset) (to prevent string dumps from a security breach, injection, etc.)

but of course neither of those solve the original problem.

Thanks for any other ideas!

ck_
  • 3,353
  • 5
  • 31
  • 33
  • technically not an answer, but you could configure mysql to accept only trusted sources, e.g. only the unix domain socket, or only using the right SSL certificate. Ontopic: See my answer for how to not store the literal password. – mvds Jul 28 '10 at 15:27
  • have you considered the possibility of some `backup.(tgz|zip)` file lying around, containing the password? – mvds Jul 28 '10 at 15:48
  • 1
    even worse than local backups would be remote backups with the text too - hence me asking the questions because plain text is just begging for trouble sooner or later – ck_ Jul 28 '10 at 15:55

8 Answers8

25

Personally, I store sensitive information such as database connection details in a config.ini file outside of my web folder’s root. Then in my index.php I can do:

$config = parse_ini_file('../config.ini');

This means variables aren’t visible if your server accidentally starts outputting PHP scripts as plain text (which has happened before, infamously to Facebook); and only PHP scripts have access to the variables.

It’s also not reliant on .htaccess in which there’s no contingency if your .htaccess file is moved or destroyed.

Caveat, added 14 February 2017: I’ll now store configuration parameters like this as environment variables. I’ve not used the .ini file approach for some time now.

Martin Bean
  • 38,379
  • 25
  • 128
  • 201
12

Keeping your config files outside of your document root is a popular way of improving the security of config files.

Paul Dragoonis
  • 2,315
  • 1
  • 16
  • 22
  • 3
    I was just typing that. I was going to point at the sub-clause that a lot, if not most shared hosts don't give their customers access to anything outside of the document root. – Peter O'Callaghan Jul 28 '10 at 15:10
  • Still you have the literal password stored somewhere in one file. That's still a higher risk than you need to take. – mvds Jul 28 '10 at 15:49
  • 1
    Peter O'Callaghan, I have dedicated server, and even I can't store outside of the document root – Nusrat Nuriyev Jan 25 '16 at 19:20
12

Since your code will need the password there is no perfect security. But you can make it hard to recover.

I put some hash in my web config, as an environment variable, say MYSQL_PASS_HASH

Then I do something like md5(getenv('MYSQL_PASS_HASH').'gibberish$qwefsdf') which is then the password. Of course you should unsetenv after that if you're paranoid.

Your password will not literally be stored somewhere, and it can be recovered only when someone has both you web config and your database include.

This happens in a file outside of the webroot (don't put all your trust in .htaccess).

mvds
  • 45,755
  • 8
  • 102
  • 111
  • I think this is the first reply so far that is a true improvement over plain text. The next problem would be making it easy enough for other users to configure like that. (Moving outside of webroot is not always possible on some hosts and is not really a true solution since if it can be included, file_get_contents will work on it too) – ck_ Jul 28 '10 at 15:33
  • 1
    @symcbean: Why? I'm posting it here, just as I configured it on my own servers! That's not obscure, but published, on SO of all places! I'm just spreading the risk over 2 files which should both not be accessible, and should never **both** be part of the same backup, **plus** not storing it in clear text. – mvds Jul 28 '10 at 15:46
  • 9
    The "obscure" part of the phrase implies to simply hide (the problem), so in reality mvds your method is technically better than simply moving the plain text outside the webroot. Just moving a file is definitely "security by obscurity". – ck_ Jul 28 '10 at 15:53
2

Certainly you should never store a password in a plain text file within the document root. What further steps you take to secure it will depend on the level of access you have to configure your webserver.

You could define the password in php.ini (or via the ini setting in the Apache config or .htaccess). Or set it in the environment when you start up your webserver.

There's no point in just encrypting the password - that means you need to store a decryption key - unless you use the user supplied password with quorum authentication to decrypt the password (but this prevents non-authenticated sessions from accessing the db, and gets messy when you need to add new users to the quorum).

If its a cheap hosting package and you have no accessible storage outside the document root then storing the password in a php include file within should prevent it being exposed (file will be parsed by php intead of downloaded). Alternately simply naming the file with a '.ht' at the beginning may prevent remote access.

Note your second option is somewhat redundant - if someone can do that much damage to your code then they don't need to extract the password from the running code.

Really there's no solution to the problem.

C.

symcbean
  • 47,736
  • 6
  • 59
  • 94
  • Like you, I concluded it's a chicken/egg problem but I wanted to see what else some of the great minds around here can come up with. – ck_ Jul 28 '10 at 15:48
  • there is clearly a point in some form of encryption, keeping two (or more) parts needed to recover the password separated as far as possible. (e.g. one part under `/etc`, the other in your include path but not in your webroot) – mvds Jul 28 '10 at 15:52
2

Besides storing this sensitive data properly, you should also create a separate MySQL user that has only the required privileges and restrict the access to the database/tables/views it needs to have access to. And since the database server is often run on the same machine as the web server, do also restrict the access to local accesses. So don’t use the user with root privileges if it just needs to read data from a single database/table.

Gumbo
  • 643,351
  • 109
  • 780
  • 844
  • 2
    Good reminder about limiting rights - because many PHP applications take the lazy way out and have the user just configure one MySQL login for everything so it can create tables, etc. But of course, even lesser rights would still need to write in most apps and great damage can be done with just that. – ck_ Jul 28 '10 at 15:43
1

If you're willing to trade off availability for file security, you could take the password out of the config file and require an administrator to type it in when booting and store it in a global variable.

You still have to make sure you're safe from injection attacks that could dump that variable out, and of course you have a manual step in the (re)boot process.

G__
  • 7,003
  • 5
  • 36
  • 54
0

It does not have to be in the webroot. You can move the file outside of the webroot and call it that way. This will just mean the file cannot be called directly from the web.

If your code has security flaws in it, such as including stuff without filtering from GET data, then that file is still at risk. The real key is making sure your application is secure as well.

Jim
  • 18,673
  • 5
  • 49
  • 65
0

You can set enviroment variables in .htaccess file, for example:

SetEnv DBuser sesame
SetEnv DBpass street

And later in your code read, use and delete the entries.

Nezumi
  • 11
  • 3