| Simple code reviews for Joomla! |
| Tuesday, 16 December 2008 19:31 |
|
The greatest risk with Joomla! lies in the usage of third party extensions. There are several ways to check if a choosen extension is secure enough. In this blog we're having a look at the PHP code - not to discuss all possible security exploits, but just to look at the general security guidelines for Joomla! extensions.
First of all it is assumed that the PHP configuration at the hosting level is secure already. This means that Register Globals is disabled, the not-so-safe Safe Mode is off, and there is some kind of "open_basedir" jail to lock Joomla! within its own directory. Every good hosting provider should provide such an environment. Only then it makes sense to take a look at the extensions. Every extension should be built following a few simple rules. Here are the rules: _JEXECEvery PHP-script within an extension - that is every file with a ".php" suffix - should start with a _JEXEC statement. It should look a little bit like the following: defined('_JEXEC') or die('Restricted access');
Though there are a few variations on this, it should always be a check "defined" (not "define") on the keyword "_JEXEC". If it is missing, the PHP-script could be called directly from the URL, opening up for lots of hacking possibilities. In most (but not all) cases this statement should be mandatory. Fetching POST and GET through JRequest
Lots of security exploits in the past relied on the fact that values from the URL (so-called $_GET variables) where not checked properly. For instance an "id" could be ment for a numeric value identifying a MySQL database record. But a hacker might try to insert a database query instead, and thus try to delete all the existing users in Joomla!. Every value exported from an external resource (GET, POST, sessions, cookies, database) into a PHP-script should be checked thoroughly. This means: If you expect "id" to have a numeric value, make sure it does. The simplest way to do this is through the JRequest-class within the Joomla! Framework. If you see in the PHP-code occurrances of the JRequest-class, at least you will know that the developer understands the above. If you see direct calls to $_POST and $_GET, it probably means the developer has never heard of JRequest, and is in general a bad Joomla! programmer. Wrong: $id = $_GET['id']; Right: $id = JRequest::getInt( 'id' ); Form tokensAnother security mechanism provided by the Joomla! Framework are tokens. A hacker might try to alter values within a form by altering the HTML-code of the webpage - we call this "spoofing". Form tokens make spoofing a lot harder (but not impossible). An example: Let's say you have a form with a certain select-box to choose a color. The select-box contains three values: "red", "green" and "blue". Now the hacker downloads the form, adds a new value "yellow" to it, submits the form from its local computer to Joomla!. Ofcourse the PHP-script should check if "yellow" is an allowed option, but this kind of spoofing should be disallowed to start with. Adding an unique token to every form would force the hacker to insert this token to the hacked form - it doesn't make it impossible to spoof the form, it just makes it harder. And that's a good thing. Every form within Joomla! should be protected by tokens. The hard part of investigating this is that form tokens appear in two places: First of all the place where the form is generated, second of all the place where the submitted form is checked. If an extension is following the MVC programming standard, the following code should appear somewhere in a "tmpl" subfolder within the folder "views" of the component: <?php echo JHTML::_( 'form.token' ); ?> With this piece of PHP-code the Joomla! token is inserted in the form. But now the component also needs to make sure that the form is not spoofed. Generally this check is done in the controller of the component (but it could also appear in the model). The controller is either a single file "controller.php" or a bunch of files located in the "controllers" folder. Somewhere the following code should check if a token was present in the form and if the token was the same as the token generated in the "view". If not, the script exits with the statement "Invalid Token". JRequest::checkToken() or jexit( 'Invalid Token' ); Just the beginningThese checks are just the beginning of clean secure code. But looking at the past 3 years of Joomla! the majority of all the exploits were based on the absence of simple security checks. And you don't have to be a security expert to make these checks. |