Interview with Deutsche Welle on WordPress Security
I recently did a short interview with Deutsche Welle about WordPress security. Listen to it here.
To expand on the topic, here are some of the details that didn’t make it into the final cut of the interview:
If your blog is compromised, you should install the latest version of WordPress, but first you should remove your old files. This is to prevent a hacker from leaving a back door (something like wp-give-hacker-access-forever.php in your WordPress directory. Just dropping the new version over the old version wouldn’t replace a new file that a hacker may have added, which is the reason for getting rid of the old files. Once you’ve done that (being careful to back up your wp-config.php and all your wp-content files), upload a clean install of WordPress. Restore your custom files. Next, look for any user accounts that weren’t there before, or that have higher access than they should. Sort that out. And lastly, scan through your theme/plugin files looking for backdoors or hidden links. This is mostly a manual process, but there are some common things to look for. Most backdoors use the eval() function, so be on the lookout for that!
The best way to keep your blog safe is to stay updated with the latest WordPress version! We’ve tried to make it as easy as possible to update (one-click!), and we have big plans for making it even easier in the future.
I’ve never had one of my WordPress blogs compromised, and I don’t do anything “fancy.” I just stay updated.
Reminder: if you’re using WordPress.com or another “hosted” blog solution, they take care of security updates for you. The only thing you need to worry about is choosing an unguessable, complex password.
PHP $_SERVER variables are not safe for use in forms, links
A common security mistake I see WordPress plugin authors (and PHP coders in general) make is using $_SERVER['PHP_SELF'] or $_SERVER['REQUEST_URI'] as the action of a form or part of an anchor’s href attribute. This is not safe to do, and opens your code up to XSS (cross-site scripting) exploits.
Common example:
<form action="<?php echo $_SERVER['PHP_SELF']; ?>">
Another example:
<a href="<?php echo $_SERVER['PHP_SELF']' ?>?foo=bar">link title</a>
Here are my two rules regarding $_SERVER['PHP_SELF'] or $_SERVER['REQUEST_URI'] in forms:
- Do not use them
- If you use one of them, escape it with
esc_url()
Most uses of $_SERVER['PHP_SELF'] and $_SERVER['REQUEST_URI'] are in HTML forms. If you want the action attribute to point to the current URL, leave it blank. URI references that are blank point to the current resource.
<form action="">
If you do want to specify the action (and there are good reasons for wanting to do that, such as stripping the query string from the current URL), you must run it through esc_url().
<form action="<?php echo esc_url( $_SERVER['PHP_SELF'] ); ?>">
The same applies to links… run the href attribute through esc_url().
<a href="<?php echo esc_url( $_SERVER['PHP_SELF'] . '?foo=bar' ); ?>">link title</a>
A quick search through the WordPress Plugin Directory showed that this problem is far too common.
Updates:
Examples of URLs that could exploit this for double-quoted actions:
script.php/"%20onmouseover='alert(document.cookie)'
And single-quoted actions:
script.php/'%20onmouseover='alert(document.cookie)'
No, just using a plain old htmlentities() wrapper is not going to help! That’s still vulnerable to XSS in certain situations. If you’re not using WordPress, you should copy the WordPress escaping functions (just remove the apply_filters() portions).
If you are using the base tag, Safari will apply that base to the blank action attribute. So if you use the base tag (I never do), a blank action isn’t going to be for you. Use what you’ve been using, but escape it.
Lester Chan has a handy snippet for the form action of WordPress plugin settings pages:
<form action="<?php echo admin_url( 'admin.php?page=' . plugin_basename( __FILE__ ) ); ?>">
admin_url() takes care of escaping for you, and is an easy way to create a full WP admin URL from a wp-admin-relative URL.
Public response to Chris Anderson’s “Free” on WordPress
I got a tip that Chris Anderson’s upcoming book Free has the following to say about WordPress:
2. Feature limited (Basic version free, more sophisticated version paid. This is the WordPress model.)
- Upside: Best way to maximize reach. When customers convert to paid, they’re doing it for the right reason (they understand the value of what they’re paying for) and are likely to be more loyal and less price sensitive.
- Downside: Need to create two versions of the product. If you put too many features in the free version, not enough people will convert. If you put too few, not enough will use it long enough to convert.
This is most assuredly not the WordPress model. Anyone and everyone can go to wordpress.org and download a completely free, completely unrestricted, and completely feature-complete version of WordPress to run for any purpose. There is no feature limited version of WordPress.
Chris might be getting confused by WordPress.com, which is a hosted WordPress solution (the biggest one, but certainly not the only one). It is true that WordPress.com charges money for certain features, such as CSS editing capabilities. But this is completely within the rights of Automattic, the company which operates the WordPress.com service. That one company is charging for certain aspects of a hosted WordPress solution does not change the fact that WordPress itself is free/open source software and has no monetization model and no tiered versioning system.
As we talked about at SXSW, Chris, it is WordPress services that are the “freemium” portion of WordPress. We give the software away, and thus create a vibrant market for third party WordPress services (this marketplace, to quote this blog’s quite literal catchphrase, puts food on my table).
Note that it would be correct to say that this is the Movable Type model, whereby Movable Type Pro and Movable Type Enterprise get features not available in the free/open source version of Movable Type.
Update: Chris fixed this error in the electronic version of Free, and it stands to reason that future print editions will have the correction. Thanks, Chris!
Escaping API updates for WordPress 2.8
The WordPress escaping API functions have been updated. Escaping is a way of using untrusted text that “neuters” anything that could do damage. Escaping is used in WordPress to avoid SQL injection and cross-site scripting/script injection (XSS), among other things.
The old functions still work, so if you were using the old ones, you’re fine. The new ones just offer you an easier to remember, more concise, and more flexible way of securing your WordPress code.
Here’s an example. Say you wanted to translate a string, escape it for use in a quoted HTML attribute, and then echo it out. In WP 2.7, you’d have to do this:
<?php echo attribute_escape( __( 'Untranslated text' ) ); ?>
In WordPress 2.8, you can just do this:
<?php esc_attr_e( 'Untranslated text' ); ?>
Shorter, plus we killed the echo and the extra pair of parenthesis! But let’s break it down.

esc_is the prefix for the new WP escaping functions.attris the context (in this case, attribute). The available contexts for 2.8 areattr,html,js,sql,url, andurl_raw._eis the optional translation suffix. The available suffixes for 2.8 are__, and_e. If you omit the suffix, no translation is performed, and your string is just returned.
More about contexts
attrmeans an HTML attribute.htmlmeans text within an HTML node, but not within an attributesqlis an alias to$wpdb->escape().urlmeans URLs for use in HTML attributes.url_rawmeans URLs for use in redirects or storage in the database (does not entity-encode).jsmeans JS, for using PHP to populate a Javascript var.
More about suffixes
Suffixes work just like the function they’re named after.
__translates the string and returns it._etranslates the string and echoes it.- The suffix is optional. A blank suffix will just return.
- Suffixes are currently only available for
htmlandattrcontexts.
Functions with translation suffixes also accept an option second parameter of a translation domain, for use in plugins.
Enjoy! Go forth and write more succinct code.
8 steps to get started as a freelance WordPress developer
I’ve had a bunch of people ask me how they could get started as a WordPress developer or consultant. Rather than answer them all individually and privately, I’m putting it up for all to see.
Become involved with the development community
Join the wp-hackers mailing list. Participate when you have something useful to say, or an interesting question/problem to pose to other WP developers. Dive in at the WP support forums. Find someone with an interesting problem, and solve it for them. If it’s a notable issue, write a blog post about how to solve the issue. Which brings me to the next task…
Blog about WordPress
I’m doing this right now! Not only is it deliciously “meta,” it can raise your profile and help you connect with other WordPress developers and users. Write about a problem you solved, or a challenge you’d like to see addressed by WordPress core or a WordPress plugin. And don’t forget to blog about the plugins you write…
Write a bunch of useful plugins
This is probably the best thing you can do to get noticed by clients. Write a useful plugin and you’ll be getting business leads for years to come. You don’t have to write a really big, complicated plugin. Write something that will make using WordPress easier, more fun, more efficient, and people will remember you. It might be good to have one more ambitious plugin to serve as an example of your skills, but certainly don’t shy away from brevity. Some of the favorite things I’ve written are between 1 and 50 lines of code. Users don’t care about how big a plugin is. They just want it to serve a need. Go ahead and scratch their itch. Hint: monitor Google or Twitter for people saying “I want a WordPress plugin…” to get an idea of the sorts of needs that are currently unfulfilled.
Contribute to WordPress core
Contributing to the WordPress core software helps you in two ways. First, it provides continuing education. WordPress is constantly evolving, and you need to stay sharp! This is a great way to learn about (and influence) the direction of the WordPress codebase. Second, it raises your profile in the WordPress community (both the developer and user communities). Be sure to blog about your WordPress core contributions. Trac is a great place to start. Maintain a calm demeanor, and don’t get too big for your britches. Don’t be the person who comes in and embarrasses themselves by closing a ticket as “WONTFIX” that was opened by a seasoned developer! Watch how other tickets evolve and you’ll figure out how it works.
Stay in contact with more seasoned developers
A lot of us are busy, but we try to make time to mentor people. We’re all well-served by a vibrant development marketplace. Don’t be afraid to contact a more experienced developer for advice. The worst that will happen is that you’ll get ignored — apologies to anyone who is in my e-mail limbo… resend it if it’s been more than a few weeks!
And as you get more experienced:
Speak at WordCamps and other events
Once you’ve gained enough kudos in the WP community, you’ll likely be asked to talk at a WordCamp event. And if you haven’t, and you think you could bring something special to the event, go ahead and ask if they need any more speakers! This will raise your profile further, introduce you to really cool people, and provide you with a bunch of business leads. BarCamps, social media gatherings, and other such events are also worth attending. The point isn’t to get up there and give a business pitch. In fact, your life might be in danger if you pull that stunt at a BarCamp. The point is to impart knowledge, connect with people, while letting your skills expose themselves naturally. And pitch away when you’re chatting up potential leads between sessions.
Charge according to your skill set and experience
Several years ago, I had the quasi-embarrassing surprise of being given a voluntary 75% per-hour raise by a client. I think they were afraid that my skills had outpaced my rate, and that I was going to get wooed away by a new client at a higher rate. Don’t make the mistake of charging too little. In fact, publish higher rates than you actually think you’re worth, and allow people to haggle you down (a little). And every time you get booked up and have to turn away business, raise your rate. If you’re in that much demand, you’re not charging enough.
Find a niche
But not WordPress security. That’s mine.
A WordPress development niche is a niche within a niche. And that means you can charge more for your more specialized skills. Examples: migrating data to WordPress. Feed kung-fu. Re-implementing a design from another system. Custom write-panel plugins. Sidebar widgets.
Force CSS changes to “go live” immediately
If you update your WordPress theme’s style.css, you may have noticed that you have to “force-reload” your site in your browser to see the changes. This is because your browser keeps a copy of the CSS cached on your hard drive. Depending on how your server is set up, it may not check for a new version of the stylesheet for a couple hours, or longer! And even if you force-reload to see the changes, visitors who have previously accessed your site may still get the old CSS. One way to solve this is to “version” your CSS file, by adding ?v=123 to the URL in the <link /> to your stylesheet. This is rather a pain to have to do by hand every time, so here is a much better way:
<link rel="stylesheet" href="<?php bloginfo('stylesheet_url'); echo '?' . filemtime( get_stylesheet_directory() . '/style.css'); ?>" type="text/css" media="screen, projection" />
This automatically updates the ?12345678 ending part every time you modify the file. Boom. Now everyone instantly sees your changes.
Typographica relaunches on WordPress
Typographica, the excellent blog for typographical nerds, has just relaunched on WordPress with a great new design by Chris Hamamoto. Asked why they switched from Movable Type to WordPress, Stephen Coles replied:
For me, it seemed an obvious switch given WordPress’ wide adoption in recent years. We’ve often had trouble getting assistance with MT, whether it’s documentation or expert advice. Because WordPress is so common, the help resources and useful plugins are simply much more accessible.
WordPress’ killer features are its community and its marketplace: thousands of free plugins, thousands of free themes, and hundreds of agencies and freelancers providing every possible WordPress development and support service you can imagine.
WordPress iPhone Skin
Check out the awesome WordPress skin that my iPhone is rocking.

WordPress skin for the iPhone 3G
It’s my understanding that these will eventually be available for sale in the WordPress Shop.
Heading to SXSW, WordPress consulting availability in mid-May
Tomorrow I’m heading off to Austin, TX for the South by Southwest Interactive Festival. If you’re going to be there, and you’re a WordPress fan, make sure you say hi and let me know what cool uses you’ve found for WordPress! The best way to find out where I am or to get in contact with me is to follow me on Twitter. Ping me in an @message if you’d like to chat.
Also, if you have need of a WordPress guru, I’m back on the market! My contract with b5media has moved to a part-time arrangement, so if you’re looking for someone to figure out how WordPress and your company or product fit together, drop me a note or track me down while I’m in Austin. I have a really exciting secret project occupying my time until mid-May, but if you can wait a few months to start your project, we can start that conversation now.




Beta testers needed for Subscribe to Comments
with 21 comments
I have a new version of Subscribe to Comments that will be coming out soon. The storage system for the subscriptions is changing (or rather, being consolidated into one method, instead of being spread into two). The good news is that this new version has zero database schema changes from WordPress core. It also adds support for double opt-in subscriptions for compatibility with German law (and possibly others). Before I release this version, I’d like some other people to test it, especially to make sure that the transition of subscription storage method works smoothly.
What I need are two or three people who meet the following criteria:
If you meet those criteria, send an e-mail to mark.stcbeta@txfx.net and I’ll get you hooked up.
Written by Mark Jaquith
April 11, 2009 at 2:10 am
Posted in wordpress
Tagged with beta, plugin, subscribe to comments, testers