Docs › Framework Reference – Security Checklist

This page aims to provide a quick reference on how to secure your PHP code, when developing Piwik Plugins

Always load the GET/POST/etc. using Piwik_Common::getRequestVar()

To be protected against Cross Site Scripting (XSS) you need to load all external variables using the function Piwik::getRequestVar().

Example: If you have a URL that looks like

piwik/index.php?module=Home&date=yesterday

If you want to read the $_GET['date'] value, don't read it directly but use Piwik_Common::getRequestVar('date')

  • see Piwik_Common::getRequestVar() implementation for more details
  • see Piwik_Common::sanitizeInputValues() if you simply want to clean a given value (not coming from GET/POST/etc.) against XSS. Note that Piwik_Common::getRequestVar() calls Piwik_Common::sanitizeInputValues().

Use the Piwik functions & bind parameters to execute SQL queries

SQL injections make it possible for attackers to modify certain unsafe SQL queries, your script executes, in such a way that it could alter data in your database or give out sensible data to the attacker. That is because of unvalidated user input.

Take a look at this code:

<?php
$idsite = $_GET['value'];
Piwik_Query( "SELECT * FROM ".Piwik_Common::prefixTable('site')." WHERE idsite = $idsite" );

An attacker could hand over a string like '1 OR 1', the query results in "SELECT * FROM piwik_site WHERE idsite = 1 OR 1", thus returning all rows from piwik_site. We're not going into details here, SQL injections are covered quite well on the web. Please take a look at the resources listed at the bottom of this post.

To safely execute SQL queries in Piwik, you have to bind all the parameters passed to the SQL queries. Use the following helper functions and provide query parameters using the $parameters array.

  • function Piwik_Query( $sqlQuery, $parameters = array())
  • function Piwik_FetchAll( $sqlQuery, $parameters = array())
  • function Piwik_FetchOne( $sqlQuery, $parameters = array())

Example of binded parameters with Piwik_FetchOne

<?php
$feedburnerFeedName = Piwik_FetchOne('SELECT feedburnerName
FROM '.Piwik_Common::prefixTable('site').
' WHERE idsite = ? and name = ?',
array( Piwik_Common::getRequestVar('idSite'), Piwik_Common::getRequestVar('name') )
);

Secure your software against remote file inclusion

Consider the following code:

<?php
// $lib_dir is an optional configuration variable
include($lib_dir . "functions.inc");

or worse still:

<?php
// $page is a variable from the URL
include($page);

The user could set the $lib_dir or $page variables and include files such as /etc/passwd or remote files such as http://www.example-hacker-website.com/whatever.php with malicious code. This malicious code could potentially delete files, corrupt databases, or change the values of variables used to track authentication status.

When using functions such as readfile, fopen, file, include, require using user data, you must be careful!

Possible solutions

  • Are you sure you really need to use a user value to include a new file?
  • If yes, check the file name against a list of valid file names. For example,
    <?php
    $valid_pages = array(
    "apage.php" => "",
    "another.php" => "",
    "more.php" => "");

    if (!isset($valid_pages[$page])) {
    // Abort the script
    die("Invalid request");
    }

  • If you must really use a variable from the browser, check the variable's value using code like the following:
    <?php
    if (!(eregi("^[a-z_./]*$", $page) && !eregi("\\.\\.", $page))) {
    // Abort the script
    die("Invalid request");
    }

Secure your software against direct access

The files of your plugins will usually be called by Piwik. Piwik is a wrapper around your software, it provides many useful features like user authentication and so on. Since developers usually test their plugins only through Piwik, they tend to forget about the possibility of calling files directly. Instead of calling your plugin by

http://yoursite.com/piwik/index.php?module=YourPlugin

crackers also might try to use

http://yoursite.com/piwik/plugins/YourPlugin/YourPlugin.php

As you can see, the PHP file will be executed directly, without Piwik as a wrapper around it. Now, if your file only contains some classes or functions, but does not execute any code, there is nothing wrong about that:

Example class

<?php
class myClass {
[SomeFunctionsHere]
}
function myFunction() {
[SomeCodeHere]
}
?>

The cracker would just see an empty page when accessing your file directly. But if that PHP file actually executes anything, he would probably see a bunch of error messages, revealing important details of your system. Under some circumstances, he might also be able to execute any code he wants to, on your system!

Conclusion: To make your plugin secure against direct access, insert this code line into the beginning of every PHP file that executes code:

<?php
// no direct access
defined('PIWIK_INCLUDE_PATH') or die('Restricted access');

// your code here

This is a recommendation for any PHP file that allows for direct execution. If in doubt, use the above!

Other tips

  • Make sure that accessing your files directly doesn't execute any function that could have an impact.
  • Use .php extension for all your PHP scripts
  • Avoid executing php code using one of the following functions: eval(), exec(), passthru(), system(), popen(), preg_replace() with "e" modifier
  • Make sure your code doesn't rely on register_globals set to On, which should be the case because PHP5 has register_globals = Off by default
  • If your plugin has Admin settings (e.g., your template includes CoreAdminHome/templates/header.tpl) then your Controller should extend Piwik_Controller_Admin.
  • Some servers will disable PHP functions for (undisclosed) security reasons. Replacement functions can sometimes be found in libs/upgradephp/upgrade.php, including _parse_ini_file(), _glob(), _fnmatch(), and _readfile(). The functions safe_serialize() and safe_unserialize() are like the built-in functions, but won't serialize/unserialize objects.

References

You may also be interested in...

Documentation feedback

Have you found an error in this page, or do you think some information is missing or not clear?
Your comments, suggestions, and ideas for improvements to this documentation are very important to us. We appreciate you taking the time to send us this information.



Keywords used to find this page: Keyword not defined


This list top keywords was displayed using a Piwik Widget "Top Keywords Widget". You can access it in your Piwik: click on Widgets, and look under the Referrers category.

Entries (RSS)