Make WordPress Core

Opened 4 years ago

Last modified 6 months ago

#39309 assigned task (blessed)

Secure WordPress Against Infrastructure Attacks — at Initial Version

Reported by: paragoninitiativeenterprises Owned by:
Milestone: Future Release Priority: normal
Severity: critical Version: 4.8
Component: Upgrade/Install Keywords: has-patch
Focuses: Cc:


(Similar to #25052 but much more focused on the implementation details)


Recommended reading:

  1. http://seclists.org/oss-sec/2016/q4/478
  2. https://www.wordfence.com/blog/2016/11/hacking-27-web-via-wordpress-auto-update/
  3. https://paragonie.com/blog/2016/10/guide-automatic-security-updates-for-php-developers

Currently, if an attacker can compromise api.wordpress.org, they can issue a fake WordPress update and gain access to every WordPress install on the Internet that has automatic updating enabled. We're two minutes to midnight here (we were one minute to midnight before the Wordfence team found that vulnerability).

Given WordPress's ubiquity, an attacker with control of 27% of websites on the Internet is a grave threat to the security of the rest of the Internet. I don't know how much infrastructure could withstand that level of DDoS. (Maybe Google?)

The solution is to make the automatic update mechanism secure even if the update server is totally owned up. As published in the third link, the core elements of a totally secure automatic update system are:

  1. Offline Cryptographic Signatures
  2. Reproducible Builds
  3. Decentralized Authenticity / Userbase Consistency Verification
  4. Transport-Layer Security
  5. Mirrors and Other Availability Concerns
  6. Separation of Privileges

However, I'm mostly interested in 1, 2, and 3. I believe 4 is already implemented (if not, this just became a lot scarier).

Proposed Solution

We're going to have to roll this out in phases, rather than all at once.

  1. Offline Cryptographic Signatures
    1. Decide on a digital signature algorithm and/or cryptography library to use.
    2. Generate a keypair for the release managers to use.
    3. Pin the public key in a major release (e.g. 4.8 or 4.9).
    4. Add signature verification to the update process, but for the first release or two, don't enforce it. Just collect data until we're sure it works for everyone.
    5. Enforce digital signatures. Then this is satisfied.
  2. Reproducible Builds.
    1. The update file should be easily reproduced by any end user.
    2. The update file and update served by api.wordpress.org should be easily verifiable.
    3. We wrote Pharaoh for auditing PHP Archives; something similar may be useful for WP updates: https://paragonie.com/project/pharaoh
  3. Decentralized Authenticity / Userbase Consistency Verification
    • See below.
  4. Make plugin/theme updates secure.

Once core updates are secure, the next step is to allow plugin/theme developers to upload their own public keys which can be used to sign their own extensions.

If you want a reference implementation, we already have a working secure automatic update system built into CMS Airship (which is GPL 3):

Decentralized Authenticity

In CMS Airship, we're totally decentralized: Every Airship maintains its own record of every update file or new/revoked public key since its inception. (This is because CMS Airship aims for maximum security.)

For WordPress, I'm recommending a federated model instead, but the concepts are mostly the same:

  1. Notaries (WordPress blogs or other services that opt in to hosting/verifying the updates) will mirror a Merkle tree which contains (with timestamps and signatures):
    • Any new public keys
    • Any public key revocations
    • Cryptographic hashes of any core/extension updates
  2. WordPress blogs will have a pool of notaries they trust explicitly. (This can be provided by your hosting provider, who runs the single source of truth for all their clients, so long as they themselves practice due diligence.)
  3. When an update is received from the server, after checking the signature against the WP core's public key, they will poll at least one trusted Notary (send a challenge nonce, current timestamp, a checksum of the update file, and any other useful identifying metadata e.g. "wp-core version 4.9.2"). The Notary will verify that the update exists and matches the checksum on file, and respond with a signed message containing:
    • The challenge nonce
    • The response timestamp
    • Whether or not the update was valid

This will be useful in the event that the WP.org's signing key is ever compromised by a sophisticated adversary: If they attempt to issue a silent, targeted update to a machine of interest, they cannot do so reliably: To pull off their attack, they have to allow the Merkle tree (that is mirrored by every Notary) to record/broadcast evidence of their attack in order for it to succeed. So while targeted attacks may still be theoretically possible, it will no longer be possible to do them silently.

In addition to a security layer, it's a deterrent against the most sophisticated threats.

Securing Plugins and Themes

This will probably be the last piece tackled. Basically: Offer the same signing capabilities to theme/plugin developers that will already be in the hands of the core team.

This can be done piecemeal (i.e. optional field on WP.org that allows them to upload their public key, generated by some tooling we provide developers). We should incentivize packages that provide their own signature by, for instance, placing them higher in the listings and/or giving them an attractive and desirable UI element that says "we're secure".

If we one day reach near-100% coverage of the WP ecosystem with digital signing, we can discuss making it mandatory.

Implementation Recommendations

Okay, this section is going to be technical so feel free to skip most of this if you're not into cryptography.

TL;DR - We need a libsodium polyfill, which Paragon Initiative Enterprises is willing to write for free if (and only if) the cost of an independent third party audit is covered by the community and/or the community's corporate sponsors.

Digital signatures

PHP, out of the box, only supports RSA signatures (via the OpenSSL extension), but doesn't support RSASSA-PSS+MGF1SHA256. PKCS1v1.5 padding is unacceptable.

It may be tempting to move towards something like ECDSA, but a mix of security concerns (the Sony ECDSA k-value reuse incident, invalid curve attacks against Weierstrass curves) makes us wary even of RFC 6979 (deterministic ECDSA).

We propose a standardized digital signature algorithm based on twisted Edwards curves. Namely, Ed25519 or Ed448 (EdDSA over the RFC 7748 curves).

Merkle Trees

The TrimmedMerkleTree in Halite is probably the best starting point: https://github.com/paragonie/halite/blob/master/src/Structure/TrimmedMerkleTree.php

Halite's Merkle tree implementations are based on the BLAKE2b hash function (a SHA3 finalist with great performance in software based on the ChaCha20 round function).


One of the following algorithms should be used where ever a checksum is required:

  • BLAKE2b
  • SHA-512/256
  • SHA-512/224
  • SHA-384

At no point should MD5 or SHA1 be considered. SHA-256 and SHA-512 are vulnerable to length-extension attacks and are not recommended.

Action Plan

First, if this plan is agreeable by WordPress's security team, we'll get to work on a libsodium polyfill that works as far back as PHP 5.2.4 (in the spirit of WordPress's backwards compatibility tradition).

Once that's finished, independently audited by cryptography experts, and released to the public, we'll work on getting the core cryptographically signed. This will require some additional tooling; the release managers will need to run a command to produce a valid signature of the update file before releasing it.

After core updates are signed and signatures are being verified, we'll build the decentralized verification layer.

Then, we can move forward with making everyone's plugins and extensions securely delivered.

Change History (0)

Note: See TracTickets for help on using tickets.