Tag: security

wp_remote_get() vs. wp_safe_remote_get()

Due to a small Twitter discussion, which started after a tweet of Pippin I realized again, the WordPress HTTP API has “safe” functions. Some days or weeks ago I’ve heard of them already, but I didn’t check on them. The topic is the following: The functions wp_remote_post(), wp_remote_get() and wp_remote_head() do have siblings, which are not documented in the Codex but only in the reference:

After the WordPress community discusses largely the top security, I was quite alarmed. What are these “safe”-functions and what do they do? What is the difference between wp_remote_post() and wp_safe_remote_post()?

How the HTTP API works

Before we start, let’s be clear, what the HTTP API actually does. In wp-includes/http.php several functions are located, with which you can perform HTTP requests. All these functions basically interact with the WP_Http() class, located in wp-includes/class-http.php.

So it is relatively easy to perform a POST request with the function wp_remote_post() and to work with the received data afterwards. Tom McFarlin has published a tutorial how to work with this function on Tuts+.

What is the difference between wp_remote_post() and wp_safe_remote_post()?

If you read the source code, you will find only one difference: wp_safe_remote_post() – and the same applies to all safe_remote functions – extends the argument array with the boolean 'reject_unsafe_urls' set to true:

As you can see, these arguments are passed to the WP_Http() class. So what does 'reject_unsafe_urls' accomplish there? Once this boolean is true, the URL gets validated by the function wp_http_validate_url().

What does wp_http_validate_url()?

Since WordPress 3.5.2 wp_http_validate_url() can be found in the core. If you read the description in the source, it says.

[The function] validate[s] a URL for safe use in the HTTP API.

How does the function perform this task? As a first step, it checks (by using wp_kses_bad_protocol()), if the URL has a valid protocol. Valid protocols are only HTTP and HTTPS. If 'reject_unsafe_urls' is not true SSL is also perceived as a valid protocol (s. wp-includes/class-http.php L186). If the protocol is not valid the function will return false.

Also a URL is considered to be unsafe, if it contains a username or a password, by which a user tries to authenticate himself. The following URL would be rejected: http://benutzername:passwort@example.com

If the host of the URL contains one of the following symbols, the URL will be rejected: :#?[]

URLs which do resolve to another port than 80, 443 or 8080 – so to speak the usual HTTP posts – will be rejected.

And this is for safety reasons?

To understand the history of the safe_remote functions it helps to study the ticket 24646. In WordPress Version 3.5.2 the core developers focused on securing the HTTP API against Server Side Request Forgeries. Lets just assume, the HTTP API would not check the protocols before firing the request and the requested URL would be dict://localhost:11211/stat. This would send the string “stat” to the locale Memcached, which usually listens to the port 11211. Since the request was locally, no firewall would prevent the server to respond to this request. To be short here: Danger! In 3.5.2 the developers closed this issue, but they overshoot a little bit. The result was, WordPress was not able to access the locale installation with the HTTP API. If you wanted to fetch your own feed using wp_remote_get() the script blocked the resource.

So they had to step back a little bit. Well, the mentioned attack above is not possible, even using wp_remote_get(). But they introduced the safe remote functions. As long as you can be sure the URL can not be used for an attack on the own system, you still can rely on wp_remote_get(), wp_remote_post() and wp_remote_head(). This is useful, if you want to perform HTTP requests, which target your own host.

But if you can not be sure about the URL, you should use wp_safe_remote_get(),wp_safe_remote_post() and wp_safe_remote_head() to raise the level of security. From now on the request is limited to the conditions mentioned above.

TLTR

If you are not sure about the URL which will be passed through wp_remote_get() use wp_safe_remote_post(). It is simply the safe way to do it.

WP Slimstat security fix

On February the 24th the security blog Sucuri published a possible way for an SQL-injection using the WordPress Plugin WP Slimstat. This problem was found up to the version 3.5 of the plugin, which has over 100.000 active installations according to the WordPress repository statistics.

WP Slimstat is a famous web analytics plugin for WordPress:

Slimstat gives you meaningful insights into your website’s visitors. Track returning customers and registered users, monitor Javascript events, detect intrusions, analyze email campaigns

Slimstat

“camu”, author of the plugin reacted immediately to the possible thread and delivered an updated version 3.9.6 and 3.9.7, which fixed the vulnerability. In a reaction, the author said:

As soon as we received Marc’s [the author of the Sucuri blog post] email, we got to work to patch the vulnerability. We apologize for any inconvenience this may have caused, and we thank Sucuri for the thorough analysis they performed on our code.

So, how was it possible, to use WP Slimstat for an SQL injection? WP Slimstat ist using a secret key to sign data, which was sent between server and client. For this, it was using the timestamp, when the plugin was activated. Although this timestamp was hashed with md5, it was not to hard to guess. To find out the secret key, one just needs to generate thousands and thousands of hashed timestamps and check, whether this is the real secret key.

Once an attacker found out the real secret key, it was not to hard to start an SQL injection according the blog post written by Marc-Alexandre Montpas.

For everyone, who is running WP Slimstat 3.9.5 or lower: It is strongly recommended, to update this plugin immediately.