1

I use a small script that fetches the credentials necessary for applications to run (MySQL databases, API credentials for 3rd-party apps, etc.):

function get_credentials($id) {
  $env = $_SERVER['DOCUMENT_ROOT'];
  $host = '/path/to/host/www';
  $local = '/path/to/local/www';  
  if (strpos($env, $host) !== false) $source = '/path/to/host/.wwwcred';
  elseif (strpos($env, $local) !== false) $source = '/path/to/local/.wwwcred';
  $index = file_exists($source) ? json_decode(file_get_contents($source), true) : false;
  return ($index ? true : false) ? (array_key_exists($id, $index) ? $index[$id] : false) : false;
}

The source (.wwwcred) is a flat, plain-text JSON file stored outside the web root with the minimum required permissions. Any application that needs to "login" to anything uses the above function to retrieve credentials; usernames and passwords are never stored inside any script/application.

My Question: Is there a more secure way to complete this task? Is there a procedure for encrypting the passwords stored in .wwwcred (and decrypt before passing)? Or is there a better approach to storing this kind of data altogether?

nmax
  • 981
  • 1
  • 11
  • 19
  • Is the server yours? Is the file outside of the docroot? – PeeHaa Jun 25 '14 at 15:27
  • dublicate: http://stackoverflow.com/questions/1432545/how-to-safely-store-a-password-inside-php-code – h.s.o.b.s Jun 25 '14 at 15:29
  • Yes - both the development and production servers are mine, and in both cases the file (.wwwcred) is outside the document root. – nmax Jun 25 '14 at 15:31
  • 1
    See the [`password_hash()`](http://www.php.net/manual/en/function.password-hash.php) function. Note -- you don't decrypt what's in the file and then compare that to what the user typed -- you encrypt what the user typed and then compare that to what's in the file. So instead of taking a user parameter and returning the decrypted password, you should take a user and password parameter and then return true if the passwords match. (I realize I'm saying encrypt instead of hash, but you get the idea.) – Alex Howansky Jun 25 '14 at 15:38
  • 1
    Thank you for these responses. @Alex Howansky I'm using password_hash() to store user pwds, but these are credentials that the app needs to actually authenticate on a db or API - I don't think a hash will work in those instances(?). – nmax Jun 27 '14 at 15:46
  • 1
    @rm -rf Searching SO did show that post, but I'm not actually storing passwords in PHP... but after actually reading it through my post is def a duplicate - sorry! – nmax Jun 27 '14 at 15:46
  • @nmax Ah ok, you're providing credentials, not validating them -- I misunderstood your question. – Alex Howansky Jun 27 '14 at 20:27

2 Answers2

1

One potential change I would make is to not store the creds in a home directory. Perhaps something under etc (maybe /etc/external/.wwwcred). Again, to add another layer of elevation prevention, I'd avoid home directories and anything under document root.

You said already that you have minimal permissions set. I'd probably create a group for all consuming apps (if it's only php, then the apache or www group should work), set the file owner to root:<your group> and set permissions to 640. If possible, I'd keep all standard users out of that group- this should be something only root and the application layer should see.

abegosum
  • 636
  • 5
  • 11
0

nmax, not very code specific but here goes.

I guess it all depends how far you want to go with the security. You could hash the credentials and keep them in a file to 1. cut down on database queries and 2. they don't get accidentally get passed around on backups and dumps etc.

If you went down the hashing route keep in mind one thing:

  • work factors

Since resources are normally considered limited, a common rule of thumb for tuning the work factor (or cost) is to make protect() run as slow as possible without affecting the users' experience and without increasing the need for extra hardware over budget. So, if the registration and authentication's cases accept protect() taking up to 1 second, you can tune the cost so that it takes 1 second to run on your hardware. This way, it shouldn't be so slow that your users become affected, but it should also affect the attackers' attempt as much as possible.

While there is a minimum number of iterations recommended to ensure data safety, this value changes every year as technology improves. An example of the iteration count chosen by a well known company is the 10,000 iterations Apple uses for its iTunes passwords (using PBKDF2)2(PDF file). However, it is critical to understand that a single work factor does not fit all designs. Experimentation is important.[*6]

As well as the above also think about:

  • Transmit Passwords Only Over TLS
  • Password Complexity

I have also attached some links on password, TLS and some other OWASP cheat sheets:

Oliver Bayes-Shelton
  • 6,135
  • 11
  • 52
  • 88