18

I want to make sure all of the data in my plugins/themes is handled securely before entering the database and before being output to the browser. My problem is that there are situations where the API handles the sanitization for you -- like when saving post meta fields -- and others where the plugin/theme author is wholly responsible for doing it -- like when saving custom settings.

For the scope of this question, I'm not concerned about validating data at the domain level -- e.g., checking that an Age field on a form is between 0 and 120, or that an e-mail address is valid. I'm only concerned about security -- e.g., escaping SQL queries to avoid SQL injection when saving to the database, or sanitizing data that's output to HTML templates to avoid XSS.

For output sanitization, I know that you always need to use functions like esc_html() and esc_attr() when echo'ing variables into HTML templates. But, what about when using template tags? Do they all sanitize the output already? If so, for which context (general HTML, tag attributes, etc)? Some functions have variants for different contexts (like the_title_attribute(), but most don't.

For input sanitization, I know that I need to use $wpdb->prepare() when making manual queries, but what about when using the Settings API to create a plugin settings page, or saving post meta fields for a custom post type?

Right now I've just been digging through Core and reading tutorials every time I use a function to find out if it sanitizes or not, but that's error-prone and time consuming. I'm hoping to find some kind of comprehensive list of all the possible situations and whether or not the API handles it. e.g.,

API validates/sanitizes

  • Saving post meta with update_postmeta()
  • Saving user meta with update_user_meta()
  • Outputting a post title - use the contextually appropriate variant of the_title()
  • etc

You have to manually validate/sanitize

  • Saving plugin options with the Settings API. Pass a callback as the 3rd parameter of register_setting().
  • Direct database queries: Wrap the query in $wpdb->prepare().
  • Outputting variables in HTML. Use esc_attr(), esc_html(), etc
  • etc

I'd also be interested to understand why the API provides it in certain situations, but not others. I'm assuming it has something to do with the unknown nature of the data, but would love to hear a thorough explanation.

4
  • I like this question. I have the same thought as you. I think if there's a such list of when we must validate/sanitize manually, that would be great. +1.
    – Anh Tran
    Sep 7, 2012 at 4:43
  • 1
    @Rilwis, please see my answer. You must always validate. Sanitisation is trickier, as 'safe' depends on context. Generally, if using the WordPress API with WordPress-known data (the_title(),the_permalink() etc) you are fine but with custom data you are not (e.g. get_post_meta()). If in doubt, sanitize your self - it can't hurt. Sep 7, 2012 at 10:07
  • @StephenHarris: I read your comment. I know that, too. But I have the same opinion as Ian Dunn. I think the main reason he asks is "do enough, no more, no less".
    – Anh Tran
    Sep 7, 2012 at 15:10
  • 1
    I actually don't mind erring on the side of caution and doing too much validation/sanitation, but I think there are cases where escaping things twice can be a problem.
    – Ian Dunn
    Sep 11, 2012 at 1:04

2 Answers 2

16
+50

There are two concepts here:

  • validation - making sure data is valid, i.e. an integer is an integer, a date is a date (in the right format etc). This should be done just before saving the data.
  • sanitisation - making the date safe for its use in the current context (e.g. escaping SQL queries, or escaping HTML on output).

Validation is, almost universally, solely down to you. You know what data you are asking from a user, and you know what data you are expecting - WordPress doesn't. Validation would be performed, for example, on the save_post hook before saving it to the database with update_post_meta, or it might be done through specifying a callback function in the Settings API, called just before WordPress saves the data.

Sanitisation is a bit more mixed. When dealing with data that WordPress natively knows about (e.g. a post's tile) you can be sure that WordPress has already made the data safe. However 'safe' depends on context; what is safe for use on a page, is not necessarily safe as an element attribute. Hence WordPress will have different functions for different context (e.g the_title(), the_title_rss(), the_title_attribute()) - so you need to use the right one.

For the most part your plug-in might deal with post meta - or maybe event data from a custom table. WordPress doesn't know what this data is or what it is for, so it certainly doesn't know how to make it safe. This is up to you. This is particularly important in using esc_url(), esc_attr(), esc_textarea() etc to prevent malicious input from being able to embed code. Since WordPress knows next_posts() is suppose to print an url to the page, it applies esc_url() - but with post meta, say, it doesn't know that it stores an url - or what you want to do with it (if printing, esc_url(), if redirecting esc_url_raw(). If in dobut - err on the side of caution and escape it yourself - and do this as late as possible.

Finally - what about saving data? Do you need to make it safe then? As mentioned you do need to make sure data is valid. But if using WordPress API (wp_insert_post(),update_post_meta() etc) then you don't need to sanitise the data - because when saving data the only sanitising you need to be doing is to escape SQL statements - and WordPress does this. If you are running direct SQL statements (say to read/write data from a custom table) then you should use the $wpdb class to help you sanitise your queries.

I wrote this blog post on data sanitisation and validation which you might find helpful - in it I talk about what's expected of you in this respect.

2
  • Hey Stephan, thanks for the explanation. That did help me understand it a little better, but what I'm really looking for is a kind of comprehensive list, like the example I gave. It seems like your approach is to make an educated guess whether or not WP handles it, or to err on the side of caution and always sanitize. I'd feel more confident about it if I had an authoritative and comprehensive list, rather than relying on my understanding of it. I'm also worried that double-escaping can lead to problems.
    – Ian Dunn
    Sep 7, 2012 at 15:10
  • I also just updated the question to clarify a few things.
    – Ian Dunn
    Sep 7, 2012 at 15:36
0

Not sure it's that thorough, but with any plugin or theme, user input should be sanitized. Database operations should be done by using the $wpdb-> methods. All $_GET and $_POST data should be sanitized.

This is more best practice for PHP programming than WordPress.

So, in conclusion, if there is a WordPress function, use it, if not, sanitize your variables and inputs yourself.

If I was too vague, please ask a more specific question.

3
  • 3
    I understand that it always needs to be sanitized, but the question is about who does the sanitization in each particular situation. Sometimes WordPress does it automatically, and sometimes you have to do it manually. I've updated the question to try and make it more clear.
    – Ian Dunn
    Sep 6, 2012 at 22:05
  • Even when using update_user_meta(), you still need to validate it, as the updated values might come from an exposed form or from a user's input. If it's a value coming from a script, such as an inside decision, from an if/else loop, then you shouldn't sanitize it.
    – Ciprian
    Sep 6, 2012 at 22:54
  • 1
    The value you pass to update_user_meta() gets passed through stripslashes_deep() and sanitize_meta() in update_metadata(), and then $wpdb->prepare() in $wpdb->update(). So, I don't think you do need to sanitize it. Am I missing something?
    – Ian Dunn
    Sep 7, 2012 at 0:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.