Category Archives: ottopress

Better Know a Vulnerability: SQL Injection

We get a lot of submissions to the WordPress.org plugin repository, and so there is often a lot of dangerous code submitted. Usually this isn’t malicious, it’s just by people who honestly don’t know that their code has problems. Understanding those problems is the first step to fixing them.

So here’s one common vulnerability we see in code submissions a lot: SQL Injection

To understand SQL Injection, let’s quote Wikipedia for a moment:

SQL injection is a code injection technique, used to attack data driven applications, in which malicious SQL statements are inserted into an entry field for execution

Here’s a piece of code made for WordPress, which is querying the database for a post:

// bad code, do not use
$results = $wpdb->get_results( "SELECT * FROM $wpdb->posts WHERE ID = $id" );

If you don’t see the problem with this code right away, then you should continue reading this post.

(Yes, this article shows the basics of the prepare() function. If you already know about the prepare() function, you might be shocked at the number of people who do not.)

The problem with SQL Injection vulnerabilities is that sometimes they can be hard to spot. The issue with the above code is actually context-dependent. The question you must answer is “What are the possible contents of the $id variable?”.

If $id = 123, then all is well.

But, if it is at all possible for $id = “-1; SELECT * from wp_users;” then you might have a real problem.

Sometimes we see code like this in submitted plugins:

// bad code, do not use
$results = $wpdb->get_results( "SELECT * FROM $wpdb->posts WHERE ID = ". $_GET['id'] );

Now, we have no idea what “id” contains, and in fact, we’re leaving that entirely up to the visitor of the site. Or the hacker of the site, in this case.

There should be no case where user-input can make it into an SQL statement without being first checked for sanity.

Sometimes, that check is easy. In this case, the ID should always be a number. So we can secure the query like so:

// kinda bad code, still, do not use
$id = (int) $_GET['id'];
$results = $wpdb->get_results( "SELECT * FROM $wpdb->posts WHERE ID = $id" );

This is relatively safe, but not the recommended solution. It’s the naive approach, because we’re thinking that hey, we can just check the value ourselves and handle it accordingly. For integers, sure, but for more complex cases we can’t. Sometimes we can’t even do it for integers, so it’s best to avoid this sort of thinking entirely.

Don’t try to sanitize your inputs to SQL functions yourself. Let the sanitization functions do it for you. WordPress includes a function called prepare() to handle this safely.

The right way:

// good code
$results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE ID = %d", $id ) );

read more

Better Know a Vulnerability: SQL Injection

We get a lot of submissions to the WordPress.org plugin repository, and so there is often a lot of dangerous code submitted. Usually this isn’t malicious, it’s just by people who honestly don’t know that their code has problems. Understanding those problems is the first step to fixing them.

So here’s one common vulnerability we see in code submissions a lot: SQL Injection

To understand SQL Injection, let’s quote Wikipedia for a moment:

SQL injection is a code injection technique, used to attack data driven applications, in which malicious SQL statements are inserted into an entry field for execution

Here’s a piece of code made for WordPress, which is querying the database for a post:

// bad code, do not use
$results = $wpdb->get_results( "SELECT * FROM $wpdb->posts WHERE ID = $id" );

If you don’t see the problem with this code right away, then you should continue reading this post.

(Yes, this article shows the basics of the prepare() function. If you already know about the prepare() function, you might be shocked at the number of people who do not.)

The problem with SQL Injection vulnerabilities is that sometimes they can be hard to spot. The issue with the above code is actually context-dependent. The question you must answer is “What are the possible contents of the $id variable?”.

If $id = 123, then all is well.

But, if it is at all possible for $id = “-1; SELECT * from wp_users;” then you might have a real problem.

Sometimes we see code like this in submitted plugins:

// bad code, do not use
$results = $wpdb->get_results( "SELECT * FROM $wpdb->posts WHERE ID = ". $_GET['id'] );

Now, we have no idea what “id” contains, and in fact, we’re leaving that entirely up to the visitor of the site. Or the hacker of the site, in this case.

There should be no case where user-input can make it into an SQL statement without being first checked for sanity.

Sometimes, that check is easy. In this case, the ID should always be a number. So we can secure the query like so:

// kinda bad code, still, do not use
$id = (int) $_GET['id'];
$results = $wpdb->get_results( "SELECT * FROM $wpdb->posts WHERE ID = $id" );

This is relatively safe, but not the recommended solution. It’s the naive approach, because we’re thinking that hey, we can just check the value ourselves and handle it accordingly. For integers, sure, but for more complex cases we can’t. Sometimes we can’t even do it for integers, so it’s best to avoid this sort of thinking entirely.

Don’t try to sanitize your inputs to SQL functions yourself. Let the sanitization functions do it for you. WordPress includes a function called prepare() to handle this safely.

The right way:

// good code
$results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE ID = %d", $id ) );

read more

Better Know a Vulnerability: SQL Injection

We get a lot of submissions to the WordPress.org plugin repository, and so there is often a lot of dangerous code submitted. Usually this isn’t malicious, it’s just by people who honestly don’t know that their code has problems. Understanding those problems is the first step to fixing them.

So here’s one common vulnerability we see in code submissions a lot: SQL Injection

To understand SQL Injection, let’s quote Wikipedia for a moment:

SQL injection is a code injection technique, used to attack data driven applications, in which malicious SQL statements are inserted into an entry field for execution

Here’s a piece of code made for WordPress, which is querying the database for a post:

// bad code, do not use
$results = $wpdb->get_results( "SELECT * FROM $wpdb->posts WHERE ID = $id" );

If you don’t see the problem with this code right away, then you should continue reading this post.

(Yes, this article shows the basics of the prepare() function. If you already know about the prepare() function, you might be shocked at the number of people who do not.)

The problem with SQL Injection vulnerabilities is that sometimes they can be hard to spot. The issue with the above code is actually context-dependent. The question you must answer is “What are the possible contents of the $id variable?”.

If $id = 123, then all is well.

But, if it is at all possible for $id = “-1; SELECT * from wp_users;” then you might have a real problem.

Sometimes we see code like this in submitted plugins:

// bad code, do not use
$results = $wpdb->get_results( "SELECT * FROM $wpdb->posts WHERE ID = ". $_GET['id'] );

Now, we have no idea what “id” contains, and in fact, we’re leaving that entirely up to the visitor of the site. Or the hacker of the site, in this case.

There should be no case where user-input can make it into an SQL statement without being first checked for sanity.

Sometimes, that check is easy. In this case, the ID should always be a number. So we can secure the query like so:

// kinda bad code, still, do not use
$id = (int) $_GET['id'];
$results = $wpdb->get_results( "SELECT * FROM $wpdb->posts WHERE ID = $id" );

This is relatively safe, but not the recommended solution. It’s the naive approach, because we’re thinking that hey, we can just check the value ourselves and handle it accordingly. For integers, sure, but for more complex cases we can’t. Sometimes we can’t even do it for integers, so it’s best to avoid this sort of thinking entirely.

Don’t try to sanitize your inputs to SQL functions yourself. Let the sanitization functions do it for you. WordPress includes a function called prepare() to handle this safely.

The right way:

// good code
$results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE ID = %d", $id ) );

read more

Language Packs 101 – Prepwork

Olanguagesne of the new features alongside the auto-update feature in WordPress 3.7 is support for “language packs”. More info about these will be coming out eventually, along with new tools for plugin and theme authors to use to manage this system (or to not have to micro-manage it, rather). A lot of this feature is yet to be implemented on WordPress.org, but the core support for it is in WordPress 3.7.

In order to use it most effectively, there’s a few ground rules that you, as a plugin or theme author, need to follow. Fortunately, they’re pretty simple.

Text-domains = the plugin/theme slug

Firstly, for language packs to work, your text-domain must be identical to the plugin or theme’s slug.

What’s a “slug”? Good question. If you examine the URL of your plugin or theme on WordPress.org, you’ll find that it looks like this:

http://wordpress.org/plugins/some-text-here

or

http://wordpress.org/themes/some-text-here

That “some-text-here” part is the slug. It cannot be changed by the plugin or theme author once the entry is created for it in the WordPress.org directory. It is a unique item to plugins/themes, and that’s how WordPress.org will be managing and naming the language files.

Therefore, your “text-domain” must be the same as that slug. In all your translation function calls, the text-domain must be there, it must be a plain string, and it must be identical to the slug of your plugin or theme on WordPress.org.

Headers

For translation to be most effective for your plugin/theme, you need to include a header in it that you may not be including:

Text Domain: put-the-slug-here

This “Text Domain” header is read and used to load your language pack files even when your plugin is not activated. This allows the headers of the plugin (like the description and such) to be translated properly when the plugin is displayed on the Plugins/Themes screen. So your international users will be able to read that text too, before ever using the code.

If you want to include your own translation files instead of using the language pack system, then this still works. The core code will look for the relevant *.mo translation files in the plugin’s directory. If you use a subdirectory, like “/languages”, then you can use a header like the following:

Domain Path: /languages

Note that the Domain Path for plugins defaults to the plugin’s own root directory, but the Domain Path for themes defaults to “/languages” to begin with. If the default works for you, then you do not need to have this header at all.

Also note that if a language file is not found for a particular configuration, then WordPress 3.7 will fall back to using the language pack system to attempt to find it. So if you only include, say, 3 languages, and there are language packs for 4 more, then those 4 more will still work.

Speaking of configuration,

Function calls: load_plugin_textdomain or load_theme_textdomain

Here is how to properly call them, with the Headers you’ll need included for good measure:

If you want to allow for translation MO files in the plugin’s own directory:

Text Domain: plugin-slug
load_plugin_textdomain( 'plugin-slug', false, dirname( plugin_basename( __FILE__ ) ) );

If you want to allow for translation MO files in the plugin’s languages subdirectory:

Text Domain: plugin-slug
Domain Path: /languages
load_plugin_textdomain( 'plugin-slug', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );

If you want to use language packs exclusively (note: WP will still check the base /wp-content/plugins directory for language files, just in case):

Text Domain: plugin-slug
load_plugin_textdomain( 'plugin-slug' );

If you want to allow for translation MO files in the theme’s languages subdirectory:

Text Domain: theme-slug
load_theme_textdomain( 'theme-slug', get_template_directory() . '/languages' );

read more

Slides: A Presentation Theme

You know, when some people are asked to do a presentation on a subject, they start by thinking about what they’re going to say, how they’re going to say it, and what their presentation will contain.

Me, I just start writing code.

I was asked to present at WordCamp Seattle, on the specific subject of the GPL. Talking about licenses is pretty dry stuff, so I came up with some ideas and such and put them down and built a presentation. No problem. But naturally, I wanted to use WordPress to present it.

read more