Storing credentials securely in WordPress plugin settings

Once again, a post which I’m adding to the site primarily to remind myself about a solution. This time, it’s about how to store passwords (and other credentials) in a WordPress database.

If you’re writing a plugin which needs to connect to a third-party service, there’s a relatively high chance that you’ll need to store access credentials somewhere. Not every third-party API allows oAuth and so there’s often a need to store username and password credentials in the WordPress database. As any good developer knows, it’s a terrible idea to store login information in any database without first encrypting it.

When I asked about current best practices on Twitter, I was pointed to a long, detailed and exceptionally well-written article by Felix Arntz, which goes into all of the detail you’ll ever need about how to encrypt—and, more usefully, how to decrypt—passwords using password salting.

Felix’s solution uses the OpenSSL ciphering in PHP to do the heavy lifting. I won’t repeat the details of his solution here, but I will link to the complete PHP class I put together which is based to 99% on his solution.

The WordPress plugin settings API

The technique for adding a settings screen for your plugin is well-documented—not least at wordpress.org—so I won’t repeat that information here. However, I needed to add the functionality from Felix’s solution so that when a new password is saved using the plugin settings page, the password is encrypted.

You can achieve this by using one of the many filter hooks in WordPress Core: namely the pre_update_option_{$option} hook in the update_option method. This allows us to rewrite a value before it gets saved to the database. In my case, the field name is shp_vacancies_password and so the filter name becomes pre_update_option_shp_vacancies_password.

This filter receives two values in my implementation: the new value to be stored and the old value which is currently saved in the database. Because I don’t want to expose the current password in the HTML source code of the plugin settings page, I don’t output it as a field value. This means that if the user updates the settings but leaves the password field blank, we need to handle an empty field value.

If the value isn’t empty, we encrypt it using the salt and the encryption key method in the Encryption class. (The salt and the key are both added to wp-config.php as PHP constants.) The method which is called by the filter hook now looks like this.

public function preUpdatePasswordOption($new_value, $old_value)
{
	if (empty($new_value)) {
		return $old_value;
	}

	$encryption = new EncryptionClass();
	return $encryption->encrypt($new_value);
}

The plugin itself uses an autoloader and a use reference so that the plugin knows where to find the Encryption class. This code has now stored the password value in the options table of the WordPress database in a secure way, and we can fetch and decrypt the value using the decrypt method in the Encryption class. We can either do so directly in the place in the code where we’re fetching the password by parsing the result of get_option, or we can handle the decryption “invisibly” by using the equivalent hook to the one we used when saving the value, namely option_{$option}.

Leave a Reply

Your email address will not be published. Required fields are marked *