2

I'm writing some code that updates options using update_option using the REST API and apiFetch.

I'm used to doing this using AJAX where I would pass a nonce along in the request to my PHP function, as well as check for current user capabilities.

Using the REST API and apiFetch feels much better than using AJAX, but I feel like I'm missing something when it comes to security.

Here's an idea of what I'm doing:

register_rest_route(
    $namespace,
    '/update_settings/',
    array(
        'methods'             => WP_REST_Server::EDITABLE,
        'callback'            => array( $this, 'update_settings' ),
        'permission_callback' => array( $this, 'update_settings_permission' ),
    )
);

My permission_callback looks like this:

public function update_settings_permission() {
    if ( ! current_user_can( 'manage_options' ) ) {
        return $this->error( 'user_dont_have_permission', __( 'You do not have permission to change options.' ) );
    }

    return true;
}

My update_settings function looks like this:

public function update_settings( WP_REST_Request $request ) {
    $new_settings = $request->get_param( 'settings' );

    if ( is_array( $new_settings ) ) {
        $current_settings = get_option( 'my_options', array() );
        update_option( 'my_options', array_merge( $current_settings, $new_settings ) );
    }

    return $this->success( true );
}

And then the request itself is quite standard:

apiFetch( {
    path: 'namespace/v1/update_settings',
    method: 'POST',
    data: {
        settings: this.state.settings,
    },
} ).then( ( result ) => {
    // all done.
} );

This all works perfectly, but it seems too easy. Should I be passing a nonce along somewhere? It seems like apiFetch has some middlewares that include a nonce - is this all done for us by default?

1
  • I don't believe this is secure, but not because of the method used, but the ability to update an arbitrary setting is itself insecure. Instead of an endpoint that accepts generic options, you should have individual endpoints for specific things. Also, you should have named the endpoint settings rather than update_settings, as it's the HTTP method not the name of the endpoint that's meant to indicate the action, e.g. GET retrieves data, POST/UPDATE/PUT adds or updates data, DELETE deletes it
    – Tom J Nowell
    Commented Nov 15, 2020 at 1:13

1 Answer 1

0

This all works perfectly, but it seems too easy. Should I be passing a nonce along somewhere?

No

It seems like apiFetch has some middlewares that include a nonce - is this all done for us by default?

Yes.

If your endpoint requires a nonce and apiFetch did not provide it, then apiFetch would not work. Authenticated endpoints using cookie based auth require nonces.

Remember, the REST API authentication and security is server side. apiFetch is client side. apiFetch cannot magically bypass the server side checks unless you deliberately added such a bypass. If you had, you would know about it and you would not have asked this question, as that would require a considerable amount of effort and intention to do.

There are security issues here, but they are unrelated to apiFetch. The use of apiFetch has not reduced your security.

1
  • Thanks for the answer! Will be sure to properly sanitize everything being saved.
    – Tom
    Commented Nov 15, 2020 at 5:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.