0

I have installed and activated the Wordpress JSON API (http://wordpress.org/plugins/json-api) in my self hosted WP site. Now my site content is open to the world via this API in JSON format.

But, I want to restrict the access of this JSON API only to the requests that are coming from specific domain. Even though someone got to know that my site has JSON API enabled and the URL endpoint, they should see 'Access Denied' except the requests comes from a specific allowd domain.

How to implement this restriction in WP?

Thanks in advance.

6
  • Not to worry. There are ways to verify the person asking for data from the server is authorized, generally with a piece of code within the header. Hang On, I'm checking the code. I love this line in there // oh please oh please oh please oh please oh please I'm going thru the code, and I don't see a lot of security checking except for the use of the wordpress nonce system. As written now, that code only requires nonce's for creating a new post and submitting it via API call. It would be easy to require that for data requests.
    – zipzit
    Commented Jun 20, 2014 at 9:05
  • Another related question. I'm assuming you have a public website with posts, pages & other content. The only content available via API call is generally the same content visible on your website. With those assumptions it would seem odd to restrict content via an API call that would be available via a simple look at your website.
    – zipzit
    Commented Jun 20, 2014 at 9:08
  • Yes, my site content is public, but if I let the JSON also open, any developer who knows the base JSON API URL can use it to create a client (Android / iOS app) which I want to avoid. Yes, creating nonce in one way is good, but that is also available for the devs to create one from the JSON API interface. Commented Jun 20, 2014 at 9:20
  • Yup, and a smart developer can scrape the data from your public web site anyway. Sorry, but nonce is the tool provided in that package shown above. A nonce is a "number used once" to protect URLs and forms from being misused. (Exactly what you are asking for...so.. what's the issue?) Look at http://codex.wordpress.org/WordPress_Nonces Remember the nonce will have to be generated at your site, sent to a user and they include it in their API request to validate their authority. A nonce is only good for two verification checks, and if unused expires in 24 hours. Its the right tool for you.
    – zipzit
    Commented Jun 20, 2014 at 9:55
  • Yup, thats exactly I was looking for. Thanks for explaining nonce usage (am a newbie) ;) Commented Jun 20, 2014 at 10:10

3 Answers 3

2

More reliable will be allowing specific IP instead of domain using REMOTE_ADDR header. You can use HTTP_REFERRER header but it is not reliable.

You can do it via using rest_authentication_errors filter.

add_filter( 'rest_authentication_errors', 'wpse150207_filter_incoming_connections' );

function wpse150207_filter_incoming_connections( $errors ){

    $allowed_ips = array( '127.0.0.1' );
    $request_server = $_SERVER['REMOTE_ADDR'];

    if( ! in_array( $request_server, $allowed_ips ) )
        return new WP_Error( 'forbidden_access', 'Access denied', array( 'status' => 403 ) );

    return $errors; 

}

The rest api will generate 403 error on ips other that given ip array.

Note: The solution works for WP v4.4.2 + Rest API v2.0-beta12.

1
  • 1
    The OP probably wanted to make sure that only people that use his site will be able to send API requests. As the request will be generated in the browser you can not really check for source IP addresses. Commented Feb 11, 2016 at 13:26
0

The software provided has tools to utilize the WordPress Nonce system. As now written, the nonce is only used there to validate the submissions of posts via an API call. The good news is that the code is well organized and it would be pretty easy to customize the code to require a nonce submission (or other security token system) for all API requests.

Note: A nonce is a "number used once" to protect URLs and forms from being misused. Ref: http://codex.wordpress.org/WordPress_Nonces Nonces are generated on the hosting site, then sent to a user, so they can include it in their API request to validate their authority. A nonce is only good for two verification checks, and if unused expires in 24 hours. There is a concern that anyone could 'ask' for a nonce, and perhaps you would have to revert to a password/id system.

== Method: get_nonce ==
Returns a WordPress nonce value, required to call some data manipulation methods.
= Required arguments =
* `controller` - the JSON API controller for the method you will use the nonce for
* `method` - the method you wish to call (currently `create_post` is the only method that requires a nonce)
= Response =
    {
      "status": "ok",
      "controller": "posts",
      "method": "create_post",
      "nonce": "cefe01efd4"
    }  

== Method: create_post ==
Creates a new post.
= Required argument =
* `nonce` - available from the `get_nonce` method (call with vars `controller=posts` and `method=create_post`)
= Optional arguments =
* `status` - sets the post status ("draft" or "publish"), default is "draft"
* `title` - the post title
* `content` - the post content (etc...)

In order for a client application to obtain data via the API (e.g. get the 'About' Page) I would expect re-written code to function in this manner:

<?php
require_once 'HTTP/Client.php';
$http = new HTTP_Client();
$http->get('http://wordpress.test/?json=core.get_page&slug=about&dev=1&nonce=cefe01efd4');
$response = $http->currentResponse();
$response = json_decode($response['body']);

echo "Response status: $response->status\n";
echo "Page title: {$response->page->title}\n";
?>
--EXPECT--
Response status: ok
Page title: About Us -- This is an awesome website.
0

For those reading this post in 2021, adding to the fine answer of @Sisir

WordPress: version 5.7.2
PHP: version 7.4

Did you try the Permission Callback ?

According to the following 2 nice sources from the WP REST API Handbook:
REST API Handbook / Extending the REST API / Routes and Endpoints
REST API Handbook / Extending the REST API / Adding Custom Endpoints


/**
 * Permission Callback function:
 * 'ypp' is the Prefix I chose (ypp = Your Private Page)
 */

function ypp_get_private_data_permissions_check() {
    /**
     * Restrict endpoint to allowed IPs (white listing approach)
     */
    $allowed_ips = array( '127.0.0.1' );
    $request_server = $_SERVER['REMOTE_ADDR'];

    if( ! in_array( $request_server, $allowed_ips ) )
        return new WP_Error( 'rest_forbidden', esc_html__( 'Access denied from your IP address.', 'my-text-domain' ), array( 'status' => 401 ) );

    return true;
};

add_action('rest_api_init', function() {
    /**
    * Register here your custom routes for your CRUD functions
    */
    register_rest_route( 'your_private_page/v1', '/data', array(
        array(
            'methods'  => WP_REST_Server::READABLE,
            'callback' => 'get_your_data', // <-- your main callback function
            // Always allow GET, for example
            'permission_callback' => '__return_true' // <-- to leave it open
            ),
        array(
            'methods'  => WP_REST_Server::CREATABLE,
            'callback' => 'insert_your_data', // <-- your main callback function
            // Here we register our permissions callback. The callback is fired before the main callback to check if the current user can access the endpoint.
            'permission_callback' => 'ypp_get_private_data_permissions_check',
        ),
        array(
            'methods'  => WP_REST_Server::EDITABLE,
            'callback' => 'update_your_data', // <-- your main callback function
            // Here we register our permissions callback. The callback is fired before the main callback to check if the current user can access the endpoint.
            'permission_callback' => 'ypp_get_private_data_permissions_check',
        ),
    ));
});

Note:
No Plugin needed anymore. The WP REST API has been merged into WordPress core.

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.