Secure Storage of Database Credentials?


#1

My application is connecting to a DB2 database via PHP (using the IBM_DB2 API).

The server discussed is not directly connected to the web; the main risk we are defending against is a compromised employee computer (that is connected to the web) being used to access the database via my application (whether using the application to read files directly, or using it to harvest credentials of privileged accounts and then proceeding to the database directly).

I’ve already set up new database accounts with minimal privileges for each unique task at hand (and have measures in place to ensure that my users must prove they have access), but I am concerned about the way I’m providing the connection arguments.

To connect to the database, I must provide arguments for the database name, user name, and user password (with user name and user password corresponding to an authorized Database account):

$this->dbName = "database_name_string";
$this->dbUser = "username_string";
$this->dbPass = "password_string";
db2_connect( $this->dbName, $this->dbUser, $this->dbPass )

I want to know if I need to store these in some other, more-secure way (and what that way would be). I’m thinking that if someone is reading my PHP files (not accessible by anyone other than myself and IT), I’m already screwed from a security standpoint. And even if they did get access to the said accounts, the accounts have read-only access to non-sensitive files.

But, if I were to extend the application’s functionality to allow access to more-sensitive files, I would want to know that I’ve handled this issue correctly. In fact, we will not extend the functionality unless we can verify that the methods we are using are secure. I also want to know if this method would be considered sloppy if it made it to production-level code.

I know I would feel better if I used some form of symmetric encryption to store the credentials in a config file somewhere, but I don’t know if that would actually improve anything at all. If we assume our theoretical attacker has hacked into my computer or an IT computer and can read our PHP to see the credentials with the first solution, wouldn’t we assume they read the php and see how to decrypt the credentials with the second solution? I guess it depends on whether or not they can gain access to wherever the credentials are stored?

Half of the reason I’m typing this is to help myself think through the problem completely, and the other half is to make sure somebody tells me where and how I’m doing things wrong, so feel free to tell me if I’m completely off the reservation here. Thanks.


#2

What about defining them as constants in another file. Then setting your permissions on that file so only PHP can access them.

define(“DB_SERVER”, “localhost”);
define(“DB_USER”, “username”);
define(“DB_PASS”, “password”);
define(“DB_NAME”, “database”);


#3

That sounds like a good idea to me. I guess it would be redundant / non-productive to encrypt the constant value? Eg set constant as define(“DB_USER”, “$encrypted_username”) and decrypt only when it’s used?


#4

Then you’d need to set the same permissions for all PHP files on the system. If file A with global permissions includes a config file B with restricted permissions then even though the attacker cannot access file B they can access file A and modify it to output the credentials in some form.

Anyway, I doubt that you can protect the credentials well enough in case an attacker breaks into a computer that stores and uses them. You can increase the number of security-by-obscurity layers but ultimately I can’t see how real security can be reached in this case.

This indicates there are multiple employee computers that store the database credentials? Then in order to protect them a solution is to dedicate one computer for a server that runs the application and the employees are connecting to it as clients. Then you can protect one server only, restrict access to it, etc., which is easier than doing it on every user computer.


#5

Gotcha.

I’m starting to wonder if I’m exposing attack vectors by explaining this more thoroughly, but anyways:

The application runs on a single dedicated computer that is accessed via URL through a local network.

There are multiple employee computers with access to a file navigator for the server where the application is run. We are worried about someone using the server’s file navigator to look at the PHP files, and gain higher-level credentials than those of the employee whose computer may have been compromised.

As of right now, this is essentially hypothetical since the only credentials currently stored in the PHP have read-only access to inconsequential files. We are examining whether or not this is a security factor to decide if we can expand the scope of the application to more sensitive files.


#6

A stolen database password is only an issue if it can be used to log in. Make it so that database connections can only be made from localhost (so just the PHP script running on the server) and your problem goes away. Even if someone has the credentials, they can’t login unless they can also ssh/vpn/somehow connect to the server running PHP first.


#7

This is how the server works by design - it is only accessible by computers that are physically present at our location, with wired connections - so by definition, any attacks will be by those who’ve gained remote access to a computer with a physical connection to the server.

Since employee computers open up connections to remote computers on occasion, I’d like to ensure that gathering credentials is just as hard as using them (in case anything goes wrong).


#8

When you say “accessible”, how are they accessed? Do those computers have write access to PHP scripts on the server?


#9
When you say “accessible”, how are they accessed?  Do those computers have write access to PHP scripts on the server?

All employee computers are connected to the web. Some are also connected to the server.

Those connected to the server have a file-navigator tool (which, every time it’s opened, asks for the username and password unique to the employee). The employee username and password has unique authorization to different parts of the database we’re trying to protect, and may have write permissions for the PHP.

If we continue to extend the PHP’s functionality, we would create new read-only credentials for use by the PHP application that could access sensitive files – and thus I was concerned about cases where the employee’s computer may be able to read a PHP file that contains credentials with access to more-sensitive documents than the (probably already compromised) employee credentials.

Of course, now that I’ve explained it fully, I’m realizing that there will almost never be a case where the access granted to a profile stored in the PHP would be of a higher level than an account with write access to my PHP files. Actually, the only people who have PHP write access already have global access…

Sigh. I’ll focus on making sure our computers don’t get compromised, I guess. Thanks for the help!


#10

Why not put the PHP files on a server completely separate from the fileserver and close all incoming ports except for 80, 443 and 22, so you can a) access the website over HTTPS and HTTP, and you can use scp or rsync or something to upload files to the server securely.


#11

Unless I’m missing something, this would result in the same behavior as keeping it on the same server.


#12

No, because less people have access to it. Unless I misunderstood you?


#13

Even when kept on the same server as the database, only IT personnel and myself have access to the PHP. Everyone else is locked out. The same would be true for a separate server.

Essentially my concern was invalid; see my reply to TomB:


#14

This sounds strange. I don’t know if you can share it but I’m wondering what’s the purpose of employees accessing files and even having write permissions for PHP? What files do they need to have access to and to be able to modify? Do they have access to all file system? I was thinking the only people needing access to PHP files are application programmers while regular employees should have a dedicated storage space - like for documents, etc. Unless the employees are also programmers?.. Which would be strange, too, since a programmer would normally access PHP files by FTP or SSH. This sounds like the employees have access to all kinds of files and directories they don’t need to - but then I don’t know the specifics of business requirements.


#15

I used the term employees to include the head of IT and myself, who are the only ones with access to the PHP files (via a wired connection to IBM i that has the PHP files and the database), whether to read, write, or modify. The PHP uses specially-created profiles with read-only access to specific parts of the database.

We don’t give anyone access they don’t need.


#16

To me this situation looks similar to a programmer who has FTP/SSH access to a server - they will also have access to any database credentials. This is normal procedure but requires trust that the programmer is savvy enough not to have his computer hacked, in which case an attacker can get access to sensitive information. In your case you need to make sure the file navigator tool does not have security holes.

A more complicated situation is when some of the programmers are not to be trusted and you want to hide some data from them.


#18

Standard security procedures:
DB credentials in a separate file, located above/beside the root of the webserver (and FTP server, if used). Prevents blindly crawling your server looking for the file to access. (you’d be surprised how many sites have “db.php” in their root folder…)
PHP reads files at an OS level, rather than being caged by the webserver, so it can reach out to a file that the webserver cant normally serve (That its user still has permissions to, obviously).
Why do this? If the PHP engine fails to initiate for some reason (software removed, maintenance window, whatever), the webserver may regurgitate code as-is, in plaintext. Yes, the rest of your PHP code will be exposed and that may make things vulnerable from a sense of people knowing the layout of the database. But at least they wouldn’t also have the keys to the kingdom and the server string to go hunt it.

Only grant your database user the privileges it needs. If it’s only reading from the database, then only allow it read permissions. That way at worst you’ve got a data breach, and not a DB loss because someone decides to wipe your tables.

Only grant access for the database user from the IP of the webserver. That way if they DO manage to get your credentials by some hoodoo, they’d have to perform the breach from inside the server itself. (And yes, as you and others have sufficiently surmised, if they’re inside the server already, you’re worrying about the window dressings while the thieves are in your bedroom.)


#19

You should also make sure no exceptions reach the end user as is, unless you’ve very explicitly coded it yourself. This is to avoid leaking any internals like queries etc to the user, allowing them to discover how the database is set up by triggering error states on purpose.

Also make sure stack traces never show, as those could contain the database credentials.

A good setting for production would be to set display_errors and display_startup_errors to 0 to prevent displaying of internal PHP errors.

Also I would suggest to run ob_start at the start of the script, initialise a custom exception handler, and if anything goes awry throw away the buffer and show a custom (generic) error page.