10

This question is generally similar to past questions asked here, but I haven't seen one the relates to Linux.

Case at hand: a PHP web app has a MySQL backend. As part of its functionality it accesses other, remote MySQL hosts and issues some queries on those hosts.

To allow that, the PHP app needs credentials for those remote databases. What is a reasonable way for it to store/fetch such credentials?

It is required that the users of the app do not provide such credentials themselves. Also, there could be dozens of users to this app.

All users of the app are identified via LDAP. The app and the entire set of MySQL servers lie within the same internal network (requires two step VPN verification). The entire setup runs on Linux machines.

What are reasonable solutions to this problem?

Shlomi Noach
  • 186
  • 1
  • 10
  • keep them in a regular database, in md5 format or something similar. Once they logged in, give them a session which would enable them to reach to remote databases? No session-no access. And you can set roles to users to determine who can access what... – cengizUzun Jan 13 '14 at 18:23
  • I don't have a problem with sessions and roles. But how would I store the remote DB credentials? I cannot do that with MD5 since I need to be able to get the cleartext. – Shlomi Noach Jan 13 '14 at 19:05
  • Do the users need to access the remote database with their *own* credentials? You could store credentials for those remote databases in configuration (just like you do for credentials to the main database), and control access to those connections through your application. – Stephen Touset Jan 13 '14 at 19:47
  • They do not. As I explained in the question, it is required that the users do not provide such credentials. They only supply LDAP credentials fro the PHP app. The PHP app will then access remote MySQL servers and perform some operations. – Shlomi Noach Jan 13 '14 at 20:25
  • cant you make their roles same on other DB's? So when I log in to app, my session would be valid in remote db's as well? Never keep creds in clear text. You can enable logging in via hashes, which is not a good practise, but better than having clear text creds. – cengizUzun Jan 14 '14 at 07:24
  • 3
    What is wrong with using MySQL+SSL, iptables and storing credentials in a config file for the web app? – David Houde Jan 15 '14 at 17:53
  • @DavidHoude, I don't know that it's wrong. But if the PHP app has access to said config file, then also a hacker of the PHP app. – Shlomi Noach Jan 15 '14 at 20:13
  • @cengizUzun, the users have no roles on the remote databases. It's the PHP app that makes the connection, on its own behalf. The users have accounts on the PHP app, and are not known entities in the remote databases. – Shlomi Noach Jan 15 '14 at 20:15
  • I've asked similar question a while ago: http://security.stackexchange.com/questions/1335/storing-third-party-auth-info-securely – StasM Jan 20 '14 at 07:29

4 Answers4

14

You just need to store the configuration in a file that is only accessible to the user that PHP is running as. You can prevent a web user from accessing the file, but PHP has to be able to get to the credentials and no matter what you do, they will be effectively unprotected. Any secret you could give the application could be discovered, so there isn't any real advantage to trying to make some complex chain.

Beyond just the configuration file, you should also ensure that the SQL account that your webserver uses can only be used from the IP of the webserver and that it only has the rights needed for the webserver. If your webserver gets hacked, then they will get the webserver's access to the DB, but if your webserver is that hacked, they could also just replace scripts to make the webserver access it however they want anyway.

AJ Henderson
  • 41,816
  • 5
  • 63
  • 110
  • Thank you. Apologies, I can't vote up right now since I don't have enough reputation here. – Shlomi Noach Jan 15 '14 at 19:50
  • This is the right approach. If you properly chmod the configuration file, keep it above the web root, and control privileged access to your system, the credentials are as safe as they can be. – Dan Jan 20 '14 at 21:56
4

I presume you are on a dedicated server? If you're on shared hosting it is almost impossible to secure PHP scripts.

A reasonable approach is to store the passwords in a dedicated configuration file and restrict the file permissions so this is only readable by the owner.

I expect people will cry "oh but they're not encrypted". The thing is, your application needs the plaintext passwords to connect to the database. So if you encrypt the passwords, you also need to have the key available, which defeats the point. I've seen all sorts of crazy proposals to improve on this, but all they do is add complexity without adding any meaningful security.

paj28
  • 32,736
  • 8
  • 92
  • 130
  • 1
    It is indeed a dedicated server. BTW, apologies, I can't vote up since I don't have enough reputation here. – Shlomi Noach Jan 15 '14 at 19:49
  • I can imagine the type of complexity you're talking about. For example, encrypting the passwords in the database and using a plaintext cipher in the config file. While it is almost meaningless in terms of security, it does group the data correctly: suppose the remote instances hostname+port are stored in your local database; putting the encrypted passwords in same table makes sense and your database can also actually vouch for their existence (ie a NOT NULL column), whereas if you put them in a config file you cannot trivially enforce such constraint. Makes sense? – Shlomi Noach Jan 16 '14 at 05:47
1

Another solution is to directly implement a ssh client within your application and depend on third party libraries such as JSch or extend either ssh/ssh-agent to directly receive and decrypt the key from your database.

*EDIT*

Important thing is what you are trying to achieve by storing the key in the database encrypted.

An attacker that is able to access the temporary private key file will be able to read the ssh client process' memory as well (and hence get to the key data anyway), because both of these data must have basically the same access permissions - trying to hide the file doesn't seem to make it any more secure.

If you are using different users for db, webapp and ssh connection, by storing the key in the db, decrypting it in the webapp and feeding it to ssh, you are just opening potential attack vectors by spreading the key all over the process. If you are using just one user for all of these (db, app, ssh), you are gaining nothing except for code complexity.

The only advantage seems to be an easier transfer of the system to a different host and potential gain in case the db data gets stolen but the webapp (which AFAIU contains the decryption algorithm and password) not. But is that likely?

That said, if you want to protect the key, you can also use the ssh's internal encryption of the keys and load them into an ssh-agent when starting your service (remember to remove it when it stops!). But again remember that the ssh-agent keeps the keys in memory unencrypted, so it can potentially be read. Yet again: is this the problem you are trying to solve?

If you just need to protect communication between two machines, stunnel might be of better service than ssh.

  • 1
    This answer needs more upvotes - mysql afaik is unencrypted, so that password is going to be sent in the clear across the network/internet, and that other host should not be listening to the internet if it can avoid it. – pacifist Jan 20 '14 at 01:00
  • 1
    mysql supports working over SSL. – StasM Jan 20 '14 at 07:29
  • MySQL passwords are not being sent in plaintext even when not using SSL. – Shlomi Noach Jan 20 '14 at 20:31
  • @Gexos, "directly receive and decrypt the key from your database" -- from which database? Do you mean the password should reside on the remote database itself? On the remote database host? – Shlomi Noach Jan 20 '14 at 20:33
  • Where ever that is, i don't mean about where the password should reside. I edited a bit my answer cause i cant right more here. –  Jan 20 '14 at 20:48
0

Generic answer about Question title

There is two way of doing this.

1. Having password not stored in the server

This could be, but of course nothing could work without this essential key!

In this case, your application server have to ask for password on each boot.

This require an human administrator responsible of starting server every time any failure occure and/or maintenance implie server reboot.

2. Having password stored in the server.

Of course, the rights level used to serve webpages is not same than right level used to manage the server!

But this is the only really important thing.

You could do some hardening: hide password by using hiden files, picture stegano, or else, but this is a little useless:

The only important thing is to prevent privilege escalation:

Once bad guy reach high privilege in your server, following step-by-step the boot process for retrieving the way used by the server for reading his credential is as easy as eating a piece of cake.

Generic answer about builded app on GNU/Linux.

The simpliest way of ensuring correct storing of all credentials on complex structured systems is simply to install Debian GNU/Linux with only base system, than install only required servers following Debian documentation first.

Once all correctly installed, I take a lot of time for browsing all docs, before doing my own configuration.

There come a test step, making them running in my local domain.

Only when I think having sufficiently understood how this work, I could place this on plublic network.