0

I'm switching my code from using wp-ajax to the REST API and got puzzled regarding the nonces. First of all, I find it weird that you have to use wp_rest only, since API has many different methods and it would make sense to use different nonces for different routes. But then I found something rather worrying: the nonce in the header is checked only if it's present, I don't get an error if I simply don't pass a nonce in my request to the API.

My JS looks like this:

function loginWithAJAX(form) {
    $.ajax({
        type: 'POST',
        url: '/wp-json/my-api/v1/login',
        dataType: 'json',
        data: form.serialize(),
        beforeSend: function(xhr) {
            xhr.setRequestHeader('X-WP-Nonce', myAjax.restNonce);
        },
        success: function(loginData) {
            location.reload();
        },
        error: function(jqXHR) {
            console.log('Error: ' + jqXHR.responseJSON.message);
        }
    });
}

It's a simplified version, just to show what I mean (and myAjax object is provided via wp_localize_script) and it works. If I replace myAjax.restNonce with an incorrect value then I get an error from the API. However, if I remove this header I get no error and I get a successful result with code 200.

So I guess I should always do an additional check in my functions to make sure that the nonce was provided. Currently I'm doing it like so:

$nonce = $_SERVER['HTTP_X_WP_NONCE'] ?? '';
if (! wp_verify_nonce($nonce, 'wp_rest'))
    return new WP_Error('rest_security_error', 'Invalid token.', array('status' => 403));

But I'm not sure, maybe I'm missing something? If the API checks the nonce only if it's provided, doesn't it partly ruins the point of having a nonce check? Not to mention that these additional checks that I would have to make would decrease (slightly, but still) the performance and fill my code base with checks that could be avoided otherwise.

And also I'm wondering if that's also true for the default routes and if they don't have these additional checks then it sounds like a vulnerability.

So, my main question is: do I have to additionally check the nonces on every request as shown above?

  • this nonce is only used to authenticate the current user and you can get it with wp_get_current_user(). if you need a security against CSRF for non-logged in users, you have to use a 2nd nonce. – mmm May 3 '18 at 9:45
  • @mmm, yes, CSRF is what I'm mostly trying to protect the website from here. I've read somewhere that using multiple nonces per form is not a good idea, but I can't remember why... Should I still then check both nonces in my routes then? Or maybe I could somehow set it globally to always check for the presence and correctness of wp_rest nonce? It would be an overkill, I guess, but if this nonce is missing then it's likely that somebody is trying something... – Dmitriy Gamolin May 3 '18 at 9:57
  • As I understand it, the default behavior is if you don't provide a nonce in ajax requests, WP will treat you as the "guest". You can do anything a guest visitor can do (like viewing posts). Anything beyond that (like editing or deleting posts) will fail. I could be wrong, though. – Betty Apr 13 at 2:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.