Our new tool finds “hidden” WordPress pages exposed by just released WP REST API

In December WordPress 4.7 was released. The most cool part of this release was the inclusion of the WordPress REST API. In development for quite some time it was finally included in core.

The WordPress REST API is great for developers because it makes it very easy to get all pages, posts and users from a WordPress site and use them in any way they want, using JavaScript or PHP or basically any programming language.

Did we say all pages? Yup, that’s right. All Most of your posts, pages and users are exposed to the public with this API. That includes pages that have no public links to them and pages that are not available in any menus on your website.

So some of the WP devs here at Earth People got curious about the API and what exposed stuff we could find on those websites on the internet that had updated to 4.7. We figured that an easy way to test this was to create a Google Chrome extension.

Hello there WP Content Discovery Chrome Extension

So we made the the extension and we called it WP Content Discovery.

Here’s how it works:
It adds an icon to your chrome toolbar. By default it only displays the letter “w” as in WordPress. When you visit a WordPress powered website and it detects the API is lightens up and displays “API” in blue.

The extension icon in action. On the first site no API is detected. On the second site the API is detected and the icon shows a blue API text.

Now the fun starts: click the icon to get get a list of pages, posts and users on that website!

Here is an example from the website of admin activity logger Simple History:

Here we can see that the extension indeed did find some pages on the website we tried it on…

Please try the extension. And please let us know what you think here in the comments!

One last thing… the API may freak some people out…

Even if all the data that you can get publicly from the REST API is already available somewhere in WordPress, it does freak some people out that it actually is possible to get the content so easily.

It is however pretty easy to disable the API if you find it to scary.


Making signed requests with CodeIgniter

Recently we’ve done lots of backends for IOS apps, Flash sites, Facebook apps and such. In most cases, it’s just a matter of responding with JSON to a HTTP request, saving or fetching something from a datasource. The problem is that it’s fairly easy to sniff the request, change a few parameters and submit a forged request. Up until now, we’ve done authentication on an ad hoc basis, but last week i whipped up a simple CodeIgniter library to standardize the way we do this authentication. Here it is.

This is how to work it:
1. Place this file in application/libraries/
2. Load or autoload it
3. In your controller, use this to validate a request:

    # keep calm and carry on
    # respond that the checksum was bad

4. Call your controller with ?checksum= or by passing checksum as a post variable.
5. The value of checksum must be calculated correctly on the client side (IOS app/Flash/etc). Bad requests are logged in application/logs, together with the correct checksum for the request.

This is how it works:
The calucation is done like this:

“fieldstring” is all the post or get variables, formatted like name=value&name2=value2&etc
post and get variables must be sorted on key name (using same algorithm as php ksort).

“salt” is the CodeIgniter encryption key, set in application/config/config.php

– This method allows the same request to be sent again, as long as it looks exactly the same. It’s pretty easy to make this library take current time into account, but would require that your CodeIgniter install and your external app do a little handshake on init, syncing the app’s timestamp to the server’s. Should you need this functionality, just put a time() somewhere in the sha1 in both the lib and the app.
–  We currently only handle the request methods GET and POST. If you need support for more verbs, you are probably capable of adding it yourself, heh.

(If you end up using this: please share your client code, and let me know so i can put up a link to it from here!)