Mark Unwin
Mark Unwin

Reputation:

Storing Passwords in reversible form

I have a PHP app that needs to run bash scripts, and provide a username & password (for remote systems). I need to store these credentials somewhere that is accessible by my PHP (web) app. The logical place is the database (currently MySQL, but will be agnostic). The problem with the "standard" way of hashing and storing the credentials, is that it is not reversible. I have to be able to get the credentials out as unencrypted clear text, to be able to insert the data into bash scripts.

Does anyone have any suggestions for a secure way to go about this ?

I thought maybe PKI'ing the credentials, and storing the result in the DB. Then use the private key to unencrypt (PHP can do that). Store the scripts to do this outside the web root.

Any thoughts much appreciated.

Upvotes: 17

Views: 6530

Answers (12)

L. Cornelius Dol
L. Cornelius Dol

Reputation: 64036

First, to state the (hopefully) obvious, if you can in any way at all avoid storing usernames and passwords do so; it's a big responsibility and if your credential store is breached it may provide access to many other places for the same users (due to password sharing).

Second, if you must store credentials prefer rather to stored passwords using a non-reversible, salted cryptographic hash, so if you data is compromised the passwords cannot easily be reverse-engineered and there's no need to store a decryption key at all.

If you must store decryptable credentials:

  1. Choose a good encryption algorithm - AES-256, 3DES (dated), or a public key cipher (though I think that's unnecessary for this use). Use cryptographic software from a reputable trustworthy source - DO NOT ATTEMPT TO ROLL YOUR OWN, YOU WILL LIKELY GET IT WRONG.
  2. Use a secure random generator to generate your keys. Weak randomness is the number one cause of encryption related security failures, not cipher algorithms.
  3. Store the encryption/decryption key(s) separately from your database, in an O/S secured file, accessible only to your applications runtime profile. That way, if your DB is breached (e.g. through SQL injection) your key is not automatically vulnerable, since that would require access to to the HDD in general. If your O/S supports file encryption tied to a profile, use it - it can only help and it's generally transparent (e.g. NTFS encryption).
  4. If practical, store the keys themselves encrypted with a primary password. This usually means your app. will need that password keyed in at startup - it does no good to supply it in a parameter from a script since if your HDD is breached you must assume that both the key file and the script can be viewed.
  5. For each credential set, store a salt (unencrypted) along with the encrypted data; this is used to "prime" the encryption cipher such that two identical passwords do not produce the same cipher text - since that gives away that the passwords are the same.
  6. If the username is not necessary to locate the account record (which in your case it is not), encrypt both the username and password. If you encrypt both, encrypt them as one encryption run, e.g

    userAndPass=(user+":"+pass);
    encryptInit();
    encrypt(salt);
    encrypt(userAndPass);
    cipherText=encryptFinal();

    and store the singular blob, so that there is less occurrence of short cipher texts, which are easier to break, and the username further salts the password.

PS: I don't program in PHP so cannot comment on suitable crypto s/w in that environment.

Upvotes: 24

Montana Harkin
Montana Harkin

Reputation: 419

For PHP, it is important to note that AES encryption is implemented via MCRYPT_RIJNDAEL functions. Don't go paying for a non-open implementation when PHP has them available.

See the PHP page discussing available ciphers for more information.

Upvotes: 0

Polsonby
Polsonby

Reputation: 22875

Just to follow up on the suggestion to use MySQL encode and decode functions, the manual is vague on just how these work:

The strength of the encryption is based on how good the random generator is. It should suffice for short strings.

But what I'd suggest is that you can instead use the built-in MySQL 5.0 AES functions; AES_ENCRYPT() and AES_DECRYPT()

SELECT AES_ENCRYPT('secret squirrel', '12345678') AS encoded

=> ØA;J×ÍfOU»] É8

SELECT AES_DECRYPT('ØA;J×ÍfOU»] É8', '12345678') AS decoded

=> secret squirrel

These use 128-bit AES which should be strong enough for most purposes. As others commented, using a salt value and a key with a high entropy is a good practice.

Upvotes: 0

Mark Unwin
Mark Unwin

Reputation: 1623

I think I am going to investigate compiling a PHP script with the credentials embedded, on the fly, from the web app.

I would ask for the credentials (for a given use), then create and compile a new PHP script, for this use only. That way, the script will only do what I need, and should not be "readable". I think this sounds like the safest way to do this.

Will try using Roadsend. http://www.roadsend.com/

Upvotes: 0

Joe Scylla
Joe Scylla

Reputation: 701

As many stated you scenario requires that you encrypt username and password. I would recommend that you check out the mcrypt extension of php for encryption/decryption.

Upvotes: 0

user33891
user33891

Reputation: 21

I would suggest you not store the passwords, but use passwordless ssh connection from the host to the remote system by generating a ssh key and storing your public key in the remote system's authorized_keys file. Then you would only need to establish connectivity during configuration. Admittedly not quite answering your question, but storing passwords in a reversible form is a slippery slope to a security breach imho, although I am sure smarter brains than mine can make it safe.

Upvotes: 2

too much php
too much php

Reputation: 91028

One easy way to get started is to use mysql's ENCODE() and DECODE() functions. I don't know what algorithm is used underneath, but it's easy enough to use:

INSERT INTO tbl_passwords SET encoded_pw = ENCODE('r00t', 'my-salt-string');

and

SELECT DECODE(encoded_pw, 'my-salt-string') FROM tbl_passwords;

Upvotes: 1

Noah Goodrich
Noah Goodrich

Reputation: 25263

It looks like you pretty much have two methods of doing this:

1) Like you suggested use an encryption algorithm or algorithms which can then be decrypted and used for authentication in your scripts. You can use the MCrypt library in PHP to accomplish this.

2) Depending on the required level of security and your script's level of vulnerability, you could use a secure hash, key, or some other hard to guess unique identifier that you can use to hijack each user's account within the confines of the script.

Upvotes: 0

Bob Probst
Bob Probst

Reputation: 9641

I think you're on target. Look at GPG for a good, open encryption library

Upvotes: 0

Paul Whitehurst
Paul Whitehurst

Reputation: 579

If you go the PKI, and I would, make sure you safe guard your private keys! The strong encryption provided by PKI is only as secure as your keys.

Upvotes: 0

Christian C. Salvadó
Christian C. Salvadó

Reputation: 827496

Check this library: PECL gnupg it provides you methods to interact with gnupg. You can easily encrypt and decrypt data, using safe public-key cryptographic algorithms.

Upvotes: 3

FlySwat
FlySwat

Reputation: 175623

You'll need to look into good 2 way cryptographic methods, and my general rule of thumb is:

If you implement your own cryptographic code you will fail.

So, find a good implementation that is well verified, and utilize that.

There is probably some good info here:

http://phpsec.org/library/

Upvotes: 15

Related Questions