如何在保存到数据库前加密WordPress选项值
Let's walk through the issues in your current code and get it working properly:
1. Incorrect Hook Usage & Parameter Mismatch
- First off, you don't need to manually call
apply_filters( 'pre_update_option_apikey', ... )— WordPress automatically triggers this hook when theapikeyoption is being updated. You can delete that line entirely. - Your
add_filterdeclares it passes 2 parameters, but yourencryptDatafunction only accepts 1. Worse, you're trying to use$old_valuein the function without defining it, which will throw a PHP error. Fix the function signature to match the parameters the hook provides.
2. Broken RSA Key Generation Logic
Right now, you generate a brand new RSA key pair every time you update the apikey option. That's a critical problem: once you overwrite the public key in your pkey option, you'll never be able to decrypt any previously encrypted data. You should only generate the key pair once (like when your plugin/theme is activated), not on every update.
3. Reversed Encryption Direction
RSA encryption is typically used as:
- Public key: Encrypts data (anyone can use this to encrypt, but only the private key can decrypt)
- Private key: Decrypts data (keep this secure, never expose it publicly)
You're using openssl_private_encrypt right now, which uses the private key to encrypt — this is backwards for storing sensitive data in a database.
Corrected Code
First, add code to generate and store your RSA keys once on activation:
// Generate RSA keys once when the plugin is activated register_activation_hook(__FILE__, 'generate_rsa_keypair'); function generate_rsa_keypair() { // Only generate if keys don't already exist if (!get_option('rsa_private_key')) { $config = [ "digest_alg" => "sha512", "private_key_bits" => 4096, "private_key_type" => OPENSSL_KEYTYPE_RSA, ]; $key_resource = openssl_pkey_new($config); openssl_pkey_export($key_resource, $private_key); $key_details = openssl_pkey_get_details($key_resource); $public_key = $key_details["key"]; // Store keys securely (private key should never be exposed publicly) update_option('rsa_private_key', $private_key, '', 'yes'); update_option('rsa_public_key', $public_key, '', 'yes'); } }
Then fix the encryption filter:
// Hook into the option update to encrypt the value add_filter('pre_update_option_apikey', 'encrypt_apikey_before_save', 10, 2); function encrypt_apikey_before_save($new_value, $old_value) { $public_key = get_option('rsa_public_key'); // Fallback: return original value if public key isn't available if (!$public_key) { return $new_value; } $encrypted_data = ''; // Use public key to encrypt the new value openssl_public_encrypt($new_value, $encrypted_data, $public_key); // Encode to base64 to avoid issues with binary data in the database return base64_encode($encrypted_data); }
Bonus: Decryption Function
To retrieve and decrypt the stored value later, use this function:
function decrypt_stored_apikey() { $encrypted_value = get_option('apikey'); $private_key = get_option('rsa_private_key'); if (!$encrypted_value || !$private_key) { return false; } $decrypted_data = ''; openssl_private_decrypt(base64_decode($encrypted_value), $decrypted_data, $private_key); return $decrypted_data; }
内容的提问来源于stack exchange,提问作者Luca Pisoni

