#42948 closed defect (bug) (fixed)
Backbone client sending empty string in X-WP-Nonce header by default in some cases
Reported by: | FPCSJames | Owned by: | adamsilverstein |
---|---|---|---|
Milestone: | 4.9.5 | Priority: | normal |
Severity: | normal | Version: | 4.9.1 |
Component: | REST API | Keywords: | |
Focuses: | Cc: |
Description
Environment
I run several instances of "headless" WP 4.9.1, all with the same configuration and set of plugins. All are hosted in a fairly standard shared environment, running CloudLinux + cPanel; LiteSpeed and LSPHP are in use with PHP version 7.0.x (latest stable). These instances feed Backbone client deployments on other domains, which are loading the versions of jQuery, Underscore, Backbone, and the Backbone client (wp-api.js) as included in WP. No authentication is being performed as the script only fetches public posts.
Issue/Steps
One of these deployments started to fail to load single posts (collections continued to work fine). I set Header add Access-Control-Allow-Headers "x-wp-nonce"
in .htaccess (which was never previously necessary, as my script does not send a nonce); this produced a 403 with error code rest_cookie_invalid_nonce
. I eventually discovered that this was because an empty string was being sent in the X-WP-Nonce header.
Possible source of issue
This function appears at line 828 of wp-api.js as of 4.9.1. When the server sends a X-WP-Nonce header with a response, the base model will compare it with the existing value (which is either undefined or null) and if it doesn't match, set it. This is causing the empty string to be stored, and sent on subsequent requests.
Workaround
To work around this, I changed my code from:
data.model.on("sync", function() { data.view = new Views.SingleView({ model: data.model }); data.view.render() });
to
data.model.endpointModel.set('nonce', null); data.model.on("sync", function() { data.view = new Views.SingleView({ model: data.model }); data.view.render() data.model.endpointModel.set('nonce', null); });
thereby setting the nonce to null before and after each sync. It appears that, in wp-api.js, the line:
if ( _.isFunction( model.nonce ) && ! _.isUndefined( model.nonce() ) && ! _.isNull( model.nonce() ) ) {
should be modified to check if model.nonce() returns an empty string by adding && ! _.isBlank( model.nonce() )
or chaning _.isNull
to _.isBlank
.
Attachments (1)
Change History (13)
This ticket was mentioned in Slack in #core-js by fpcsjames. View the logs.
7 years ago
#4
@
7 years ago
Thanks for the bug report @FPCSJames - I'll try to work on this soon - I'm also curious to discover why a blank X-WP-Nonce header is being sent in the first place.
#5
@
7 years ago
- Milestone changed from Awaiting Review to 4.9.5
In 42948.diff:
- Don't set the returned nonce if it is blank.
I looked thru the code the creates and returns the nonce and it should never be blank - https://core.trac.wordpress.org/browser/branches/4.9/src/wp-includes/rest-api.php#L788 - unless you have a plugin that is overwriting the pluggable wp_create_nonce function.
@FPCSJames can you give my patch a test and see if it resolves the issue you are seeing?
#6
@
7 years ago
I do not have any plugins overriding wp_create_nonce.
I tested your patch, but unfortunately, it did not work. My original suggestion, checking whether the nonce is empty before options.beforeSend is set, does work.
I believe I found the real issue. Keep in mind that in my use case, I'm embedding wp-api.js and my code outside of a WP deployment, so wpApiSettings is statically generated. Right now, that's only defining the root and versionString parameters.
In wp.api.init(), the line:
attributes.nonce = args.nonce || wpApiSettings.nonce || '';
checks to see if init() is called directly with a nonce argument (it's not - undefined), if it's defined in wpApiSettings (it's not - undefined) and defaulting to an empty string otherwise. Therefore, from what I can tell, either that line needs to change to default to null instead of an empty string, or my change of isNull to isEmpty in sync() needs to be applied.
#9
follow-up:
↓ 10
@
7 years ago
Sorry, posted the same ticket number twice… The second one is #43266.
Oops - bit of a mistype on my last sentence. "chaning" should read "changing", and I meant to cite
_.isEmpty
. It should be "or changing_.isNull
to_.isEmpty
".