WordPress.org

Make WordPress Core

Opened 3 years ago

Closed 7 months ago

#18577 closed task (blessed) (fixed)

Updates and downloads should be delivered securely

Reported by: wplid Owned by:
Milestone: 3.7 Priority: normal
Severity: normal Version:
Component: Upgrade/Install Keywords:
Focuses: Cc:

Description

All channels for downloading Wordpress installations and plugins (e.g. from downloads.wordpress.org) should either be signed or delivered securely (e.g. via SSL) to mitigate man-in-the-middle attacks. Such attacks can lead to arbitrary code execution.

It appears that currently, downloads and automatic updates are neither signed nor delivered securely.

Change History (36)

comment:1 dd323 years ago

  • Component changed from General to Upgrade/Install
  • Keywords 2nd-opinion added
  • Type changed from defect (bug) to enhancement

In quite a lot of cases (This is from personal experience whilst debugging issues people have with the HTTP API) Server configurations don't actually allow for proper HTTPS communication. HTTPS will be available, but the certificates will not be processed to ensure they're signed (just valid, so a MITM attack could insert a cert with the right name and pass). That isn't a WordPress configuration issue, rather a PHP configuration/PHP Module configuration issue (The fact that WordPress can reliably make outgoing connections on many hosts is surprising in itself honestly).

I'll leave the floor open for others on signing though, I know there are a few people who follow trac who have had a lot more dealings with SSL outgoing connections too, so we can probably detect when we can definitely use verified SSL.

I'm marking this as an enhancement, simply due to it not being a "fault" condition in existing code, simply something which could be done better, and/or make a better product.

comment:2 johnbillion3 years ago

  • Cc johnbillion@… added

comment:3 follow-ups: samuelsidler9 months ago

  • Cc samuelsidler duck_ westi aaroncampbell nacin added

We should re-visit moving API calls, updates, and plugin/theme updates over SSL. There might be some installs that break, but we can check for that internally. Server-side, wordpress.org is ready for the switch over if we decide to do it.

Westi updated the relevant URLs (from http to https) in the beta tester plugin, to get a feel for what breaks. But there would be more logic required in core to ship SSL.

For example, we'll probably want to check if SSL is broken on the server and, if so, stop allowing automatic updates. In that scenario, we'd still ping the API but if an update was available, we'd link to a hardcoded (in core) download URL and tell the user they must update manually. We should also consider adding some explanatory text, helping the user understand their situation and recommending they contact their host.

comment:4 in reply to: ↑ 3 rmccue9 months ago

Replying to samuelsidler:

For example, we'll probably want to check if SSL is broken on the server and, if so, stop allowing automatic updates.

This is the case for any server without cURL (as per mdawaffe's talk). I've found this is somewhere between 15-30% of servers, unfortunately. (fsockopen supports SSL if OpenSSL is installed, but as mdawaffe noted, it doesn't check the certificate correctly.)

I'd say that we should use HTTPS where possible, and fall back to HTTP if needed while letting the user know (probably a notice on update-core.php).

comment:5 follow-up: dd329 months ago

Other than using SSL, what options do we have to sign/validate that the packages downloaded from WordPress.org are legit?

Realistically, we cannot guarantee that 100% of Servers out there have cURL installed, and have a valid SSL cert chain locally which cURL can reference, the amount of users that affects is significant enough that we simply cannot disable updates for them.

If there is an alternative which we can use to securely verify packages after downloading, it'll make HTTP vs HTTPS not be an issue and we'll be able to trust it.

comment:6 in reply to: ↑ 5 rmccue9 months ago

Replying to dd32:

Other than using SSL, what options do we have to sign/validate that the packages downloaded from WordPress.org are legit?

If we really care, we can use asymmetrical cryptography and distribute a public key. This is possible in PHP userland with something like phpseclib and means we can avoid rolling our own for the most part. (This also falls back to native support if it exists.)

This does mean partially reinventing the wheel (this is what SSL is for, after all), but at least it gives us compatibility. The question is whether we care enough.

comment:7 follow-up: dd329 months ago

The question is whether we care enough.

And thats the key.

If we really care about this, it has to be 100% or nothing in my mind, If we just use SSL when available, a MITM attack could render the HTTPS requests inoperable, triggering a fallback condition.
The fallback options are either plain HTTP (Which would be the most compat and user friendly option) or a non-user-friendly "Sorry, go do it yourself" option - and lets face it, those on servers which cannot do HTTPS connections are generally going to be the people who need auto-updates in the first place.

Although we want to / need to verify the packages, I personally hold user experience higher than a potential MITM attack on a server which the user probably doesn't control.

This is possible in PHP userland with something like ​phpseclib and means we can avoid rolling our own for the most part.

Just saying in passing, phpseclib is also used by the plugin which replaces cores php_ssh2 update transport with a pure php transport method for 100% server compatibility.

comment:8 in reply to: ↑ 7 rmccue9 months ago

Replying to dd32:

If we really care about this, it has to be 100% or nothing in my mind, If we just use SSL when available, a MITM attack could render the HTTPS requests inoperable, triggering a fallback condition.

Keep in mind, if we do it via signing in a higher layer, we also need to think about things like key revocation.

Just saying in passing, phpseclib is also used by the plugin which replaces cores php_ssh2 update transport with a pure php transport method for 100% server compatibility.

See #21610 and #16925 for that.

comment:9 rmccue9 months ago

Initially, I was thinking that this might cause problems with load, especially for downloads. However, if we generate a key statically (that is, it's not time-based), then we can use this fairly freely with regards to that. As for performance, I'm not sure how fast generating signatures dynamically is, but I suspect not fast enough to perform in userland PHP. Ideally, this could be run on the upstream server (nginx for api.wordpress.org).

There are tonnes of projects that sign their downloads with GPG and make that signature available, so this seems like a fairly tried-and-tested solution. There is a GPG extension in PECL, but no other support. As far as I know, OpenPGP is just a layer on top of the actual encryption, so we *could* look at implementing that (which has partially been done), but that smells a lot like implementing our own encryption (duck_ may know further on this one).

I think for now:

  1. Start signing core and plugin releases on .org, which can be done statically when the zips are built
  2. Include the public key for releases (in an unfilterable manner, most likely in version.php or similar).
  3. Start checking the signature for downloads against the public key

While this is being worked out, we can hopefully do performance testing to indicate whether it's viable to sign all requests. Regardless of SSL, we should probably be checking a signature anyway.

Thoughts?

comment:10 in reply to: ↑ 3 westi9 months ago

Replying to samuelsidler:

We should re-visit moving API calls, updates, and plugin/theme updates over SSL. There might be some installs that break, but we can check for that internally. Server-side, wordpress.org is ready for the switch over if we decide to do it.

Westi updated the relevant URLs (from http to https) in the beta tester plugin, to get a feel for what breaks. But there would be more logic required in core to ship SSL.

For example, we'll probably want to check if SSL is broken on the server and, if so, stop allowing automatic updates. In that scenario, we'd still ping the API but if an update was available, we'd link to a hardcoded (in core) download URL and tell the user they must update manually. We should also consider adding some explanatory text, helping the user understand their situation and recommending they contact their host.

This wasn't quite launched yet, I didn't want to break something just before we launched 3.6 :)

api.wordpress.org will now return https urls for assets when API requests are made over SSL.

I'm going to push out the new beta tester build which forces SSL for the api requests next.

comment:11 westi9 months ago

v0.97 of the Beta Tester plugin is now available, it SSL's all the things.

comment:12 follow-up: bpetty9 months ago

Both Bluehost and DreamHost have been working on setting up a caching layer in front of downloads.wordpress.org in their respective datacenters for the purpose of not effectively sending a denial of service when automatic updates are enabled (or just when major releases are pushed out for core, plugins, or themes).

If you take the approach of using SSL transport for verification, those caching layers will no longer work, and we'll be back to denial of service against downloads.wordpress.org.

So, for what it's worth, I would advise leaning more towards package signing.

Besides that though, requiring SSL verification against WordPress.org still doesn't actually provide protection against hijacked WP.org accounts pushing back doors into releases. I've seen this attack used on occasion against popular plugin developers using weak passwords.

comment:13 in reply to: ↑ 12 ; follow-ups: samuelsidler9 months ago

Replying to bpetty:

If you take the approach of using SSL transport for verification, those caching layers will no longer work, and we'll be back to denial of service against downloads.wordpress.org.

downloads.wordpress.org should be able to handle that traffic and if it can't, that's an additional problem that should be fixed.

So, for what it's worth, I would advise leaning more towards package signing.

Why not both? If an install has working SSL, we can do everything over SSL, including sending signed packages. If they don't, we can send signed packages over the clear.

Besides that though, requiring SSL verification against WordPress.org still doesn't actually provide protection against hijacked WP.org accounts pushing back doors into releases. I've seen this attack used on occasion against popular plugin developers using weak passwords.

That's another problem that needs to be addressed, but is separate from this ticket.

comment:14 in reply to: ↑ 13 rmccue9 months ago

Replying to samuelsidler:

Why not both? If an install has working SSL, we can do everything over SSL, including sending signed packages. If they don't, we can send signed packages over the clear.

Agreed, the reality is that SSL is something we have to layer on top that gives us additional security, but not something we can rely on.

I'm happy to work on a proof-of-concept for the WP side if we're happy with this style of signing.

comment:15 in reply to: ↑ 13 bpetty9 months ago

Replying to samuelsidler:

downloads.wordpress.org should be able to handle that traffic and if it can't, that's an additional problem that should be fixed.

Feel free to ping @nacin about this.

Also, if that's fixed, I'm all for both SSL transport *and* package signing.

comment:16 samuelsidler8 months ago

  • Summary changed from Updates and downloads should be signed or delivered securely to Updates and downloads should be delivered securely

I'm splitting this ticket up. I've filed #25052 on the signing of packages and left this one about delivering things over SSL.

comment:17 follow-ups: GregLone8 months ago

Hi there.

It seems I (and at least one other person on the forum) have a problem with the v0.97 of the Beta Tester plugin.
The new version 0.97 breaks the plugins search, favorites, tags, popular, etc, and I've got the error message "An unexpected error occurred...".

The site is running WP 3.7-alpha-25000 on a local server (on a NAS), reachable from outside (dyn-dns), behind a Basic Http Auth, no SSL on the server.

Digging into the plugins_api() function, I can get the wp_remote_post() response:

WP_Error Object
(
    [errors] => Array
        (
            [http_request_failed] => Array
                (
                    [0] => SSL certificate problem: self signed certificate in certificate chain
                )

        )

    [error_data] => Array
        (
        )

)

I also tried with a clean WP 3.6 with no other plugins and Twenty Thirteen on the same server with no more luck (or may I say with the same luck? We're hunting bugs after-all ).
Disabling the Basic Auth doesn't help.

If you need some more infos...

Have a good day.
Greg

comment:18 in reply to: ↑ 17 ; follow-up: samuelsidler8 months ago

Replying to GregLone:

The site is running WP 3.7-alpha-25000 on a local server (on a NAS), reachable from outside (dyn-dns), behind a Basic Http Auth, no SSL on the server.

DLink NAS? Per @dd32, the system likely only has a DLink CA and not any root's CA. That sucks.

We'll have to bundle our own root CA to ship anything that uses SSL. (See other comments above.)

comment:19 in reply to: ↑ 18 GregLone8 months ago

Replying to samuelsidler:

DLink NAS? Per @dd32, the system likely only has a DLink CA and not any root's CA. That sucks.

Nop, Synology DS412+

Even so, I guess the self signed certificate on my NAS is to blame?

comment:20 dd328 months ago

I've seen it with dlink NAS's, but Synology and Buffalo NAS's probably have the exact same issue.

For outgoing HTTPS connections to work on those platforms we'll need to bundle the root certificates.

comment:21 follow-up: dd328 months ago

The challenge here is duplicating the issue.. I'm not sure how to compile PHP/cURL on a VM so that it's so broken..

comment:22 in reply to: ↑ 21 ; follow-up: GregLone8 months ago

Replying to dd32:

The challenge here is duplicating the issue.. I'm not sure how to compile PHP/cURL on a VM so that it's so broken..

Unfortunately that's out of my reach. But if I can help by giving some infos related to my NAS...

comment:23 in reply to: ↑ 22 ; follow-up: rmccue8 months ago

Replying to GregLone:

Replying to dd32:

The challenge here is duplicating the issue.. I'm not sure how to compile PHP/cURL on a VM so that it's so broken..

Unfortunately that's out of my reach. But if I can help by giving some infos related to my NAS...

If you have access to the internal filesystem, seeing what's in /etc/ssl/certs/ and /etc/ssl/openssl.cnf would probably help.

As to reproducing this, you should be able to empty the /etc/ssl/certs/ directory and put your own root CA in there instead. WP should bundle cURL's cacert.pem, which is built from Mozilla's CA Cert project (used in all major browsers).

comment:24 in reply to: ↑ 23 GregLone8 months ago

Replying to rmccue:

If you have access to the internal filesystem, seeing what's in /etc/ssl/certs/ and /etc/ssl/openssl.cnf would probably help.

Thanks. I'm a total n00b when it comes to command line but I'll give it a try.

comment:25 dd328 months ago

As to reproducing this, you should be able to empty the /etc/ssl/certs/ directory and put your own root CA in there instead.

Thanks, duplicated all the issues now that i've cleared that.

Added a start of a patch, and more discussion on SSL verification on #25007.

Leaving this ticket for discussion specifically related to delivering secured packages.

comment:26 in reply to: ↑ 17 ; follow-up: tieptoep8 months ago

  • Cc tieptoep added

It seems I (and at least one other person on the forum) have a problem with the v0.97 of the Beta Tester plugin.
The new version 0.97 breaks the plugins search, favorites, tags, popular, etc, and I've got the error message "An unexpected error occurred...".

I've got the same problem (got here through WP Beta Tester) as described here. My webhost simply doesn't allow SSL with my (shared) hosting plan. I don't think that having to go back to manually upgrading is something you should do to a lot of users.
I'm not that technically inclined, but it would seem to me that fallback to HTTP would be far more desirable than forcing manual upgrades on users who have even less technical knowledge than me.

comment:27 nacin8 months ago

  • Milestone changed from Awaiting Review to 3.7
  • Type changed from enhancement to task (blessed)

comment:28 GregLone8 months ago

Ok, the CA of my NAS isn't in /etc/ssl/certs/ but in another folder.
Luckily, Synology provides a way to change the CA in use, in a settings panel. And I was able to download the Synology self-signed CA from there. CA Syno.
On the other hand, I couldn't find the opennssl.cnf yet, it isn't in the ssl folder, it contains only .key, .sh, .crt and .csr files.

comment:29 in reply to: ↑ 26 bpetty8 months ago

Replying to tieptoep:

I'm not that technically inclined, but it would seem to me that fallback to HTTP would be far more desirable than forcing manual upgrades on users who have even less technical knowledge than me.

As @dd32 mentioned, these defeats the entire purpose of using SSL transport at all. Worst case scenario, it would only allow non-SSL if upgrading manually with appropriate warnings and confirmation. If it used fallback non-SSL automatically, there's just no point in even using SSL at all, and we'd just scrap this ticket entirely, and stick to package signing only.

comment:30 bpetty8 months ago

  • Cc bpetty added

comment:31 dd328 months ago

these defeats the entire purpose of using SSL transport at all. Worst case scenario, it would only allow non-SSL if upgrading manually with appropriate warnings and confirmation.

my personal opinion is:

  • We need to get HTTPS working regardless, so we'll have to bundle a CA cert #25007
  • For user-triggered updates, Fall back to HTTP in the event that OpenSSL is not available in PHP - Package signing would probably not be possible in that case either unless someone comes up with a pure-PHP-no-extensions-needed signing/verification routine
  • For non-user-triggered updates (automatic updates), only proceed if the package is retrieved over HTTPS AND a package signature is proper

So this ticket isn't dependant upon HTTPS now, I don't see HTTPS vs Package signing as an either-or thing, we need to get HTTPS running as best we can, but we also need to cover the case where downloads are over HTTP, since, although #25007 will go a long way, it won't cover every use case.

comment:32 juliobox8 months ago

  • Cc juliobosk@… added

comment:33 toscho8 months ago

  • Cc info@… added

comment:34 betzster8 months ago

  • Cc j@… added

comment:35 dd327 months ago

In 25308:

Switch to using HTTPS connections for Plugin and Theme API requests when SSL is available. See #18577

comment:36 dd327 months ago

  • Keywords 2nd-opinion removed
  • Resolution set to fixed
  • Status changed from new to closed

To summarise this ticket:

  1. #25052 - WordPress downloads should be signed
  2. [25308] - WordPress API requests should use SSL / downloads should be delivered over SSL (API's return HTTPS links when accessed via HTTPS)
  3. #25007 - Not all WordPress installs can make SSL requests, lets fix it
  4. #22704 - WordPress Automatic Updates - should only work over SSL, that's a task on that ticket

Marking as fixed, if you wish to continue following one of the above issues, head on over to it's ticket.

Note: See TracTickets for help on using tickets.