Securing WordPress

WordPress has been getting a lot of bad press the last few days, as a worm is out in the wild exploiting a security vulnerability. This is leading to somewhat unfair comparisons with Windows, and thoughtful articles from John Gruber and Maciej Ceglowski.

To be sure, the ease of programming in PHP leads a great many people to contribute to projects, who may not have the experience or security awareness they should. This is not helped by poorly designed features in PHP that were enabled by default in previous versions, and cannot always be disabled outright due to legacy compatibility concerns, reminiscent of the persistent security woes due to the C standard library’s insecure old string processing facilities.

For many users, migrating away from WordPress may not be a practical option. My recommendations would be:

  • Reduce your exposure by exporting a static HTML version of your site, as suggested by Maciej. This is really only simple if you use a non-default permalink structure that does not use question mark characters in URLs, like that used by the SEO plugins. Otherwise you would need quite a bit of mod_rewrite jiggery-pokery to get it to work. In any case, this will also disable quite a bit of functionality on your site, such as comments.
  • If you are an Apache user, install modsecurity, a truly outstanding Apache module that acts as a firewall of sorts and will inspect requests for suspicious behavior like SQL injection attempts and malformed requests. Configuring modsecurity is not for the faint of heart, but there are some papers online like this one by Daniel Cuthbert (PDF) that walk you through this. This is probably the single most significant thing you can do to make your WordPress blog safer.
  • Practice security in depth — keep regular backups of both your wordpress directory and database, so you can recover in case of attack, and if possible run WordPress in an isolated account with minimal privileges.

Mozilla Weave

Mozilla Weave is a project of the Mozilla Labs to build synchronization of bookmarks, tabs, passwords and so on between multiple instances of the Firefox browser. It used to be a private beta, but with the release of version 0.4 recently, it has been opened up to the general public.

Where version 0.2 was pretty rough, 0.4 actually works quite well, even if it is not yet feature complete. Bookmarks and passwords are handled just fine. Furthermore, you can set up your own server, all that is needed is PHP. Previous versions required WebDAV support, and the WebDAV module in nginx is not functional enough for Weave (or anything else, for that matter).

The first synchronization is painfully slow, but once it is done, later synchronizations are essentially instant. When combined with the Awesome bar’s tagging components, it has completely supplanted Del.icio.us for my bookmarking needs (I never liked the rewritten user interface).

Thomas Pink weave cufflinks

Amusingly, I came across these cufflinks at Thomas Pink in San Francisco last Friday — they are the mirror image of the Weave logo.

Thomas Pink weave cufflinks

Below are the relevant sections of my nginx config.


magic_quotes_gpc = Off
session.auto_start = 0
file_uploads = On
error_reporting = E_ALL & ~E_NOTICE
allow_url_include = Off
allow_url_fopen = Off
session.use_only_cookies = 1
session.cookie_httponly = 1
expose_php = Off
display_errors = Off
register_globals = Off
disable_functions = phpinfo
error_log = /home/majid/web/logs/php_error_log


root /home/majid/web/html;
location ~ .php$ {
  auth_basic		"gondwana";
  auth_basic_user_file	/home/majid/web/conf/htpasswd;
  fastcgi_index		index.php;
  fastcgi_param		SCRIPT_FILENAME  /home/majid/web/html$fastcgi_script_name;
  include		/home/majid/web/conf/fastcgi.conf;
# Mozilla Weave
rewrite ^/weave/admin$	/weave/admin.php;
location /0.3/api {
  return		404;
location /0.3/user {
  fastcgi_index		index.php;
  include		/home/majid/web/conf/fastcgi.conf;
  fastcgi_param		SCRIPT_FILENAME	/home/majid/web/html/weave/index.php;
  fastcgi_param		SCRIPT_NAME	/home/majid/web/html/weave/index.php;
  if ( $request_uri ~ "/0.3/user/([^?]*)" ) {
    set $path_info	/$1;
  fastcgi_param		PATH_INFO	$path_info;


fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx;

fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

@font-face embedding

I updated my wife’s home page to use embedded fonts (in this case the Fonthead GoodDog typeface for headings) with the @font-face CSS primitive. With the introduction of Firefox 3.5, all the major browsers now support embedded typography.

As usual, Microsoft had to do its proprietary thing in Internet Exploder and devised a crackpot font format called EOT (Embedded OpenType), ostensibly at font foundries’ request, with weak DRM-like metadata that allows the font supplier to restrict which sites the font can be used on. Microsoft has an incredibly convoluted tool called WEFT (Web Embedded Font Tool) to do this, but I used the open-source and incredibly easy to use ttf2eot tool instead. The only hitch in this case was that this tool takes a TrueType TTF font as input, and GoodDog is a (PostScript-ish) OpenType OTF instead. Fortunately, TypeTool can do the conversion.

We finally have semi-decent typography on the web without having to embed images (bad for page load times or accessibility) or the even worse sIFR hacks using the noxious Adobe Flash. The only question remains whether type foundries will follow. Fonthead has enlightened licensing policies for GoodDog (free for up to 5 sites, no insistence on DRM). Typeface design is a painstaking craft and designers certainly deserve what they charge for their fonts, but I hope the typographic industry does not follow the RIAA in its self-destructive crusade against its own customers.

Update (2011-03-03):

One option for hassle-free embedded font licensing is TypeKit. It does require JavaScript in the browser to work, unlike a pure CSS solution like the one I used, but the convenience can’t be beat. We use it on Apsalar’s public website.

Feedburner down again

I just tried unsuccessfully to subscribe to a feed hosted by the annoying bozos at FeedBurner. From my Temboz feed error counters, it seems FB feeds have been failing with 503 errors for at least the last 5 hours or so, par for the course.

Just another reason why outsourcing vital services to the cloud is not always a good strategy.

gondwana ~>GET -eUS http://feeds.feedburner.com/Fooducate
GET http://feeds.feedburner.com/Fooducate
User-Agent: lwp-request/1.39

GET http://feeds.feedburner.com/Fooducate --> 503 Service Unavailable
Connection: close
Server: NS_6.1
Content-Length: 62
Client-Date: Thu, 30 Apr 2009 01:31:18 GMT

<HEAD><TITLE>An Error Occurred</TITLE></HEAD>
<H1>An Error Occurred</h1>
503 Service Unavailable

Update (2009-04-30):

It is possible the problem lies with my ISP (although I could replicate it at work as well). I can ping FB from my Joyent accelerator but not from home where my Temboz instance runs.

A work-around is to use the newer Google server feeds2.feedburner.com instead. For Temboz, all you need to do is run sqlite3 rss.db and the command:

update fm_feeds
set feed_xml=replace(feed_xml, 'feeds.feedburner.com', 'feeds2.feedburner.com')
where feed_xml like 'http://feeds.feedburner%';

The importance of short iteration feedback cycles

I blog at best once or twice a month on my regular low-intensity blog, which runs my home-grown Mylos software, but am surprising myself by blogging on an almost daily schedule with this WordPress-based blog. Mylos is batch-based: you edit a post, run the script to regenerate the static pages, review, edit and iterate. It takes a minute to regenerate the entire site.

This is a similar effect to using an interpreted language like Python or PHP vs. a compiled language like C or Java. Even though I am more comfortable editing in Emacs (used by Mylos) than in a browser window, the short cycle between edit and preview in WordPress makes for a more satisfying experience and encourages me to blog more freely.

I suspect I will end up importing my Mylos weblog into WordPress, once I figure out how to address some niggling differences in functionality, such as the way images or attachments are handled, and how to use nginx as a caching reverse proxy in front of WordPress for performance reasons.