I spent several hours last week rescuing two WordPress blogs (this blog and GastroGrrl) that had both been exploited, and had become victims of nefarious spam links.
h2. WordPress Exploit
The exploit was remarkably clever. Only when Google’s search engine spider (googlebot) visited the site, did it include spam links at the footer of the page. The links were only visible when looking at the text-only version of the cached copy in google’s index. The reason I’d found the spam, was because the keywords showed up in the Google Analytics application, and GastroGrrl was no longer appearing in google’s index.
The exploits were a couple of files found on the web server – disguised as jpg and png image files – that were in fact malicious PHP scripts. The scripts went as far as adding a new user to the database.
I had no alternative except to completely reinstall both the WordPress application, and also the database. Twice. Not much fun.
The installs were up to date, though a few months ago, I was late in updating the software. Yesterday, WordPress announced another security update to version 2.6.5.
Along with the release, was a note that the version number had skipped from 2.6.3 to 2.6.5 due to a malicious, fake version of a 2.6.4 release existing online. Several months ago, an official WordPress download was hacked on the official servers, and exploits were widely distributed.
h2. Open Source Risk
Keeping open source weblog applications, like WordPress, up-to-date, can become quite an administrative overhead for those that manage client blogs. As weblogs have moved into the business/PR/marketing domain, many of those managing the blogs are not fully-fledged system administrators with the knowledge on how to secure their database or unix file permissions. This is a potential risk to the customer.
The problem is not limited to WordPress. OSCommerce, Drupal, Joomla – all popular open source applications – have all had exploit issues. This is not so much because the applications are poorly coded; it’s the nature of open source – anyone can examine the code. The more popular the application, the more likely it will be exploited.
In my work with Stan, when we discuss client requirements, we consider 3rd party open source solutions versus bespoke development. Much of the decision is based on the specific requirements, but increasingly, we also consider the security risk, and maintenance overhead.
A simple example is the ubiquitous CAPTCHA utilities found on web forms. They are an obvious target for spammers, who want to leave spam comments on weblogs etc. Open source CAPTCHA’s became a popular way to thwart such spam, and have become increasingly complex as they face a continuing battle with the spammers. In my opinion, this problem has now gone full circle. When applying a CAPTCHA solution to a web form, I choose *not* to implement a standard, open-source solution, opting instead for my own, less complex, easier to exploit, implementation. It may be easier to exploit, but who is going to bother?
Open source is great. My day-to-day development utilises numerous open-source applications. However, when a customer’s reputation is at stake, and indeed our client relationship, one has to ask the question – is open source software a risk to your business?
Tags: linkedin, open source, spam, wordpress
There is one potential pitfall here, and that is if you site generates complete URLs, or if you use a complete URL to switch to HTTPS/HTTP. My only other recommendation would be to use “*=://” instead, as that would capture non-http(s) links as well. However, that be _less_ correct than your method, depending on what other types of resources you link to (RSS, for example).
forgive my ignorance but what does rel external do? Am I right to assume that it signals that the link is to an external site but does that mean that the browser is supposed to respect the links and open in a new window. I’m guessing not. So if a customer wants those links to open in a new window this javascript will allow that. How do you cater for people without javascript? Or is this just something that you cannot implement for non js users if you adhere to the strict DTD?
@Alun, A few good questions there. Without javascript, or web browser preferences, Strict DTDs do not allow links to be opened in a new window, as this is seen as an event i.e. not part of the document structure.
rel=”external” doesn’t actually do anything. The rel attribute defines the ‘link type’. According to the W3C Spec:
‘User agents, search engines, etc. may interpret these link types in a variety of ways. For example, user agents may provide access to linked documents through a navigation bar.’
There is a list of recognised link types, such as stylesheet. ‘external’ is not a recognised link type.
http://www.w3.org/TR/REC-html40/types.html#type-links
I bet some of the new browsers will soon offer the facility to identify such links though.
[...] second solution I came across fixed some of the issues of the first by re‐writing the regex to account for [...]
Another possible attribute name is
xlink:show=”new”
from the XLink spec.
This will search your entire page for external links and make them open in a new window. Try it out!
$(function() {
$(“a[href*='http://']:not([href*='"+location.hostname+"'])”).click( function() {
window.open(this.href);
return false;
});
});
Man, that is sweet. Thanks!
This is my favorite solution to this problem, because it uses JQuery, and doesn’t assume the XHTML capable browser has implemented HTML4 “target” attribute on links.
Remember – if you happen to generate an external link or two dynamically after the page loads, the new link won’t “pop” into a new window – unless you bind the click event to the external links with live().
$(‘a[rel*=external]‘).live(‘click’, function(){
window.open($(this).attr(‘href’));
return false;
});
This ensures that any new elements are bound to the modified click event, too.
I find this nice way to do it:
$(“a[rel*=external]“).attr( “target”, “_blank” );
It’s valid, since target is still an attribute in the DOM definition.
If you don’t want to use _target at all (cause it is kinda cheating, isn’t it?), this is what I did:
$(“a.pdf”).mouseover(function() {
pdfLink = this.href;
$(this).attr(“href”,”#”);
});
$(“a.pdf”).click(function() { window.open(pdfLink); });
$(“a.pdf”).mouseout(function() {
$(this).attr(“href”,pdfLink);
pdfLink = “”;
});
You pick your target (for me, it was things that linked out to PDFs, so I had a class called ‘pdf’). On mouseover, you put the href into a variable, you strip the href from the tag so that the link doesn’t open in the parent window as well. On click, you open that variable in the new window. On mouseout, put the variable back in the href.
Since we’re using JavaScript anyways, it’s a solution that avoids _target completely, and it allows for a functioning link if the user has JavaScript turned off.
Hope it helps someone!
Cheers,
Brendan
$(document).ready(function(){
$(‘a[rel*=external]‘).click(function(){
this.target= “_blank”;
});
@ Frank
The live() method has some flaws so you might need to use delegate() when working with arrays of elements like this:
$(‘.storycontent’).delegate(“a[href*='http://']:not([href*='"+location.hostname+"'])”, ‘click’, function() {
window.open($(this).attr(‘href’));
return false;
});