We’ve been alerted that certain vendors are using suboptimal secret management techniques to handle (H/T)OTP encryption keys, which leads to them not bringing any additional security value.
Examples we’ve received include storing the encryption key on the database alongside the shared secret it encrypted or using the same key for all sites using the plugin. We pinged vendors about this, and they confirmed they would fix it in future versions.
However, upon trying to model the risk these issues represent for everyday site owners, we concluded that fixing them is more of a defense-in-depth recommendation than a security flaw they can appropriately fix.
After receiving a few similar submissions, and a lot of deliberating on our part, we’re announcing today that we won’t be processing vulnerabilities relating to less-than-ideal 2FA secret encryption practices anymore.
Our reasoning stems from reading RFC4226/RFC6238, which essentially states:
We also RECOMMEND storing the keys securely in the validation system,
and, more specifically, encrypting them using tamper-resistant
hardware encryption and exposing them only when required: for
example, the key is decrypted when needed to verify an OTP value, and
re-encrypted immediately to limit exposure in the RAM to a short
period of time.
The key store MUST be in a secure area, to avoid, as much as
possible, direct attack on the validation system and secrets
database.
Particularly, access to the key material should be limited
to programs and processes required by the validation system only.
Put shortly; they recommend encrypting the keys when possible but ask that the key must be stored in a secure area. The latter part is the most problematic in our view; what is a secure area in WordPress?
One of the risks of not encrypting the shared secret (or storing the encryption key with it) is that if an SQL Injection vulnerability is exploited on that site, attackers could potentially bypass the 2FA mechanism altogether by forging their own token.
The proposed fix that often comes up is storing the key on the file system, but what if, instead of only an SQL Injection vulnerability, the site has a Local File Disclosure problem too? An attacker could leak those files, getting the encryption secret and database credentials via wp-config.php.
It feels like storing the encryption key on the file system remains preferable because it at least resolves the case of single SQL Injection issues and mimics what WordPress itself is doing with authentication cookies. It, however, isn’t a silver bullet either. Ideally, vendors could rely on other information sources to hide sensitive keys, like environment variables, but the variety of hosting configurations available makes it pretty unlikely to work.
Considering we handle a lot of submissions daily, doing a lot of back-and-forth with vendors to fix what is essentially a recommendation more than a real problem that can be properly fixed is not something we’ll do anymore.