23

I'm currently developing a plugin and the chances are that I will more than likely release it on the public plugin repository so others can use it.

The plugin will be using an API and to use this API you need to pass a username and password. So my plugin needs to store these login credentials in the database. I don't want to store these in plain text although the API needs them in plain text.

So my question is how do I store these sensitive bit of information? Hashing is out, so it has to be some sort of encryption.

In WordPress is there a unique key that can be used that will differ from blog to blog? What php functions should I use to encrypt and decrypt? I'm looking for functions that will more than likely work on all WP installs.

10
  • 3
    This is kinda unsolvable. It doesn't matter how much you encrypt if it needs to be reversible. If WP can decrypt it and WP is compromised then encryption doesn't matter.
    – Rarst
    Commented Aug 5, 2011 at 12:57
  • But why does your API need to know the password? Isn't it enough if the API knows that the user knows the password? Commented Aug 5, 2011 at 13:02
  • 1
    @One Trick Pony - The password needs to be stored so the process can be automated without user intervention.
    – Scott
    Commented Aug 5, 2011 at 13:05
  • 1
    @Rarst - I'm aware that if WP is compromised then so are the passwords. I cannot prevent this. What I can prevent is that if an SQL dump is obtained then the passwords are not in plain text.
    – Scott
    Commented Aug 5, 2011 at 13:08
  • @Brady yep, if only SQL dump is compromised then encryption would help. However I find such scenario unlikely. If you have database access it is trivial to compromise WP as well.
    – Rarst
    Commented Aug 5, 2011 at 13:15

3 Answers 3

7

While I agree with the previous answers, to answer the question you actually asked, what comes to mind is to use one of these constants for wp-config.php:

define('AUTH_KEY',        'redacted');
define('SECURE_AUTH_KEY', 'redacted');
define('LOGGED_IN_KEY',   'redacted');
define('NONCE_KEY',       'redacted');

They are meant to be unique across wordpress installations - and are about the only options for pre-existing keys to be found in wordpress. Alternate would be to add your own similar constant that is built by hashing one of them against the admin email address or similar - and then storing that in a hidden setting option -- to protect against losing your key if someone accidentally modifies the keys after your plugin is installed. The danger is, that if they were not made unique on the initial install, but the admin / site owner decides to rectify the failure after the fact, they shouldn't accidentally break your password encryption.

As for encryption / decryption functions - a quick Google search returns the following listing with code that appears to fit the bill: http://maxvergelli.wordpress.com/2010/02/17/easy-to-use-and-strong-encryption-decryption-php-functions/

function encrypt($input_string, $key){
    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    $h_key = hash('sha256', $key, TRUE);
    return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $h_key, $input_string, MCRYPT_MODE_ECB, $iv));
}

function decrypt($encrypted_input_string, $key){
    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    $h_key = hash('sha256', $key, TRUE);
    return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $h_key, base64_decode($encrypted_input_string), MCRYPT_MODE_ECB, $iv));
}

Here's some documentation of the AES encryption used here: http://www.chilkatsoft.com/p/php_aes.asp

5

This is exactly the circumstance OAuth was designed for.

From the OAuth homepage:

For Service Provider developers...

If you're supporting...

  • web applications
  • server-side APIs
  • mashups

If you're storing protected data on your users' behalf, they shouldn't be spreading their passwords around the web to get access to it. Use OAuth to give your users access to their data while protecting their account credentials.

The advantage of OAuth is that you don't need to store the user's password. When they first set up the plugin, they're asked to log in with a username and password through the application (usually a page hosted on the same server as the API and loaded either in a page redirect, a thickbox, or an iframe).

Once the user is logged in, the server (your system) creates a secure key that their system (WordPress) can use to interface with the API. This key is unique to the user account and the site - and it gives the application (on WordPress) permission to do things with the API on the user's behalf without passing their authentication information each time.

If you want to see an example of this in action, check out Jetpack.

When you activate the plugin, it complains its not connected. When you "connect" it, you enter your credentials through WordPress.com and set up the OAuth interaction between WordPress and their API.

But you only have to do this once and your WordPress.com username/password is never stored in your local WordPress database.

2
  • 1
    Would be nice to use this but the API I'm dealing with isn't mine and they have no OAuth system in place.
    – Scott
    Commented Aug 5, 2011 at 13:48
  • 1
    In that case your only real option is to accept that you need to store the password in the DB and whether or not you encrypt it really makes no substantive different to security. As other have mentioned above, if it's in the db and the encryption is reversible, then anyone with access to WordPress (legitimate or hacked) could conceivably get a hold of it.
    – EAMann
    Commented Aug 5, 2011 at 16:35
0

This is an important issue, as many services still do not support OAuth and storing passwords in the options database makes them readable to every single Wordpress plugin (see my comment above).

This is not (yet) a real answer to the question, but also too long for a comment. I hope to spark a discussion with this, with the aim of coming up with the "best" possible solution to this "unsolvable" problem.

The basic idea that makes me think that encrypting passwords is possible is the following:

There is one piece of secret information every user has: their Wordpress password. It should be possible to store credentials to third party services encrypted with a secret derived form that password and only decrypt them when the user is logged in.

In this way it should be possible to at least make it impossible to steal the passwords from a copy of the Wordpress files and database. It cannot solve the problem of other plugins stealing credentials, because every plugin can capture the plain text password during login.

Actually decryption is rather easy to do: Suppose we already have an encrypted version of the third-party service stored in the database, we can hook into the 'authenticate' filter or by overwriting the wp_authenticate() function, generate a salted hash of the plain text user password (by means of wp_hash_password()), store that hashed password as an encryption key somewhere private until the user logs out (use the 'wp_logout' hook to delete the key) and use it every time we need the third-party password to decrypt the encrypted value in the database.

While I have the feeling it should be possible to make this work, there are however several unsolved problems:

  1. How to do the encryption? Potentially one could store the plain text password until the user logs out and in again and do the encryption during 'authenticate'. The user could be prompted to log in to keep the period until this happens short.
  2. Where to store the key and how to delete it during log out? Do I understand correctly that 'authenticate' is only run when the user actually logs in?
  3. In case there is now way to store the hashed password, maybe one can instead derive a key from the session cookie?
  4. Who to handle password changes? It looks like it is possible to catch such password changes, and the third-party password would then have to be re-encrypted with the key derived from the new password.
  5. Is there a way to provide multi user support? Ideally one would want an admin user to be able to set third-party passwords in the settings that can then be sued by less privileged users to interact with third party services, ideally even without disclosing those passwords to them. For this, the admin user would need to be able to generate a keys for all users that those other users can only generate for themselves. Is that somehow possible?
2
  • Another issue with this: although you can catch password changes, if the user has completely lost their password and then does a password reset, there would be no access to the old password in order to decrypt and re-encrypt with new password.
    – tobek
    Commented Feb 26, 2020 at 5:44
  • True. The same applies to any other password manager type software.
    – cgogolin
    Commented Mar 2, 2020 at 21:52

Not the answer you're looking for? Browse other questions tagged or ask your own question.