views:

1096

answers:

12

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.

+13  A: 

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/

FlySwat
I'm sorry, could you speak up. I missed that.
TrickyNixon
It deserves shouting.
eyelidlessness
+3  A: 

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.

CMS
Thanks CMS - will have a look.
A: 

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.

Paul Whitehurst
A: 

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

TrickyNixon
A: 

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.

Noah Goodrich
+1  A: 

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;
too much php
ENCODE just wraps crypt.
FlySwat
You're misusing the term "salt". I think you mean "key"
Jesse Weigert
+2  A: 

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.

+17  A: 

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).

If you must store 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.

Software Monkey
A: 

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.

Joe Scylla
A: 

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/

Mark Unwin
A: 

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.

Flubba
A: 

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.

Montana Harkin