CartPress Sends no-cache Headers


WordPress Plugin News Feed Stops Website Caching

It’s hard to believthecartpress sends no-cache headers icone a simple news feed from the CartPress e-commerce plugin for WordPress prevents WordPress from caching pages. This is apparently what happened to a website recently.

We received a request for assistance for a WordPress e-commerce site with this problem. The owner read our article; Fastest WordPress Caching System – and asked if we thought it would overcome a problem with his site. We explained this system wasn’t suitable for e-commerce.

The WordPress Caching Problem

The website was caching fine up to early 2013, then stopped caching. In March we provided some pro-bono help, and the bug seemed to be fixed. 6 weeks later the bug had returned. After trying every possible cache plugin, the owner was getting desperate.

The site had lost 80% of its traffic this year, and sales were way down. Without caching (and cache pre-load) the site was very slow (I’m talking about 6 to 8 seconds page load on average, and sometime worse).

Investigating the Caching Problem

We had a quick look at the website, and found http headers had no-cache parameters set

Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache

This http header prevents caching systems from caching a website page.

The site owner described what he’d already done to fix the problem; disabling all other plugins (except the essential e-commerce system plugin, CartPress) and re-installed the plugins. He’d changed to a default WordPress theme, spoken to his hosting company, all the usual things to fix WordPress bugs and conflicts.

This was starting to sound complicated and time-consuming, so our estimate was high. The new client accepted the price, just asking we gave it urgent attention.

Testing and Discovery

The ran the normal WordPress de-bugging tests – disabling every other plugin, changing themes… The we turned off the CartPress plugin – and the no-cache header disappeared!  All other plugins and the theme were re-instated, and the no-cache header was still missing.

Turn the CartPress back on – and “no-cache” was back. Now we had a clue to the problem. The plugin was deleted and replaced with a fresh upload (using FTP), still “no-cache”. We tried older versions of the plugin without success. So what was going on?

The site was downloaded to our local server, and searched every file for anything in the scripts that set no-cache. Then tried looking for that expiry date; Thu, 19 Nov 1981. Nothing was found. None of the plugins, Word Press or theme was setting no-cache headers

There was only one possible thing left – the database. At this point I was getting worried we had under-quoted. Database work can take a lot of time. But when we quote an amount, that’s the most we charge.

The Fault was in the Database

We ran SQL search commands looking for no-store, “no-cache, must-revalidate”  – and immediately found a single reference – in the wp_options table.

Problem! You cannot drop the wp_options table without losing a lot of data needed for a site – all the WordPress plugin settings get lost if you do this.

The next thing was examining the database code directly. The database was opened in a plain text editor, and we searched for the strings – Database size was 27MB, so there’s a lot of text.

Bad Code Found in Database

The problem causing entry in the databse was found in a _transient section dealing with News feed for the CartPress plugin; here’s an extract;

thecartpress.com/feed/";s:3:"rel";s:4:"self";s:4:"type";s:19:"application/rss+xml";}}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:44:"http://purl.org/rss/1.0/modules/syndication/";a:2:{s:12:"updatePeriod";a:1:{i:0;a:5:{s:4:"data";s:6:"hourly";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:15:"updateFrequency";a:1:{i:0;a:5:{s:4:"data";s:1:"1";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}}}}}}}}s:4:"type";i:128;s:7:"headers";a:15:{s:6:"server";s:5:"nginx";s:4:"content-type";s:23:
(Full content Shortened)
"text/xml; charset=UTF-8";s:10:"connection";s:5:"close";s:7:"expires";s:29:"Thu, 19 Nov 1981 08:52:00 GMT";s:13:"cache-control";s:62:"no-store, no-cache, must-revalidate, post-check=0, pre-check=0";s:6:"pragma";s:8:"no-cache";s:10:"x-pingback";s:34:"thecartpress.com/xmlrpc.php";s:4:"etag";s:34:""94fc2c087410480c4f6f625f694e1535"";s:12: and so on

(Note – http:// prefixes removed from URLs to stop WordPress auto-linking)

You can see the no-cache header originated from an RSS feed from thecartpress.com. The question is, why did they include this in a feed. Were they wanting to tell users of the plugin something about setting no-cache headers? Was their website, or their feed hacked? Was this a hack using the known cross-site scripting vulnerability in the plugin

We don’t know the answer, so must speculate. Whatever the reason for sending this header, it caused a lot of grief, and cost the website owner a lot of cash to fix.

Site Fixed and Caching:

After running several MySQL commands to remove all data from transients (our MySQL analyst was busy on another job, so I had to step in and fix this one myself – and I’m no MySQL specialist), I decided to dump the table (backup) then clear all the data.

Then I copy/pasted all the essential data, minus the transients, back in the table (this was done on our testing system, not the live site) and tested the result – It worked.

Then I edited the live site wp_options table the same way (after another full backup). And I’m very happy to say the site is now working perfectly again, with no caching problems.

WordPress Database Structure to Blame

We contend the real fault lies in WordPress core, and the way plugin news feeds are stored in the database – in the wp_options table. This table is used to store settings for WordPress and plugins.

Storing feeds as _transients in wp_options table opens up the website to malware injection. And this is exactly what this was – malware script injection to MySQL. It may have been unintentional, but the result was code injection.

WordPress and Matt should address the storing of feeds urgently. This data doesn’t need storing in the database – it can be loaded live when accessing the WordPress Dashboard. If that is as a problem, then feeds must get stored in a separate table.

Using a dedicated table for plugin news feeds will prevent these sort of things happening. WordPress reads wp_options, and takes code to run the site. A separate table could be sanitized, and read as pure data.

Final Note:

The job took about 16 hours in total. I’m sure our SQL bloke would have been a little quicker. I decided to cut the bill to the client, and charged for 12 hours work. The final bill was a third of the original estimate, so we have a happy client: website fixed and saved a lot of too. And we have more work to harden security, and move the site to our secure, faster hosting.

me on google plus+Mike Otgaar

Advertisements

About Mike

Web Developer and Techno-geek Saltwater fishing nut Blogger

Posted on July 5, 2013, in WordPress and tagged , , , , , , , , , , . Bookmark the permalink. 1 Comment.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: