Preventing Attacks on Joomla! 1.5 Websites

Exclusive offer: get 50% off this eBook here
Mastering Joomla! 1.5 Extension and Framework Development

Mastering Joomla! 1.5 Extension and Framework Development — Save 50%

The Professional Guide to Programming Joomla!

$26.99    $13.50
by James Kennard | March 2010 | Joomla! Content Management Open Source

In this article by James Kennard, author of Mastering Joomla! 1.5 Extension and Framework Development, we will investigate some of the more common forms of attack and how we can prevent them from affecting our extensions and we will take a look at how we can deal with users whom we believe to be attackers.

Whether or not we like to think about it, there is always the potential threat of an attacker gaining access to our Joomla! websites. The most common way in which security is breached in Joomla! is through third-party extension security flaws.

Due to the number of extensions that have security defects, there is an official list of extensions that are considered insecure, available in the FAQ sections at http://help.joomla.org.

It is very important that, as third-party extension developers, we take great care in making our extensions as secure as we can.

How to Avoid Common Attacks

The security flaws that we will investigate are some of the most likely to be exploited because they tend to be the easiest to initiate and there is plenty of literature explaining how to initiate them.

The attack types described here should not be considered a complete list. There are many ways in which an attacker can attempt to exploit a system. If you are concerned about attacks, you should consider hiring a security professional to help evaluate security vulnerabilities in your extensions.

Using the Session Token

A session is created for every client that makes a request. Joomla! uses its own implementation of sessions; integral to this is the JSession class. The session token, also refered to as the 'token', is a random alphanumeric string that we can use to validate requests made by a client. The token can change during a session.

Imagine that an attacker uses a utility to bombard a site with data; the data itself may not be suspicious. The attacker may just be attempting to fill your database with worthless information. If we include a hidden field in our forms with the name of the token, we can check if the user is submitting data via a form with a valid session.

We can get the token using JUtility::getToken(). In our template, where we render the form we want to secure, we add this:

<input type="hidden" name="<?php echo JUtility::getToken();
?>" value="1" />

When we call JUtility::getToken() we can optionally provide the Boolean forceNew parameter. This will force the generation of a new token. Before doing this we must consider the context in which we are calling the method. If there are any other forms present on the page that also use the token we may inadvertently prevent these from working. Components are always rendered first so are generally safer when forcing a new token.

Now all we need to do is verify the token when we receive a request from the form that we are trying to secure. In this example we specifically get the token from the $_POST hash, guaranteeing that the token came via the correct method. The error message is not very intuitive; this is purposeful, because it makes it harder for an attacker to determine the reason why they are receiving the error.

if(!JRequest::getVar(JUtility::getToken(), false, 'POST'))
{
JError::raiseError('403', JText::_('Request Forbidden'));
}

Code Injection

Code injection occurs when code is included in input. The injected code, if not properly sanitized, may end up being executed on a server or on a client. There are a number of different ways in which injected code can compromise a Joomla! installation or a system with which we are interacting.

We will take a look at the two most common forms of code injection used to attack Joomla!: PHP and SQL code injection.

PHP Code Injection

We should use JRequest and, in some cases, REs to ensure that the input data that we are handling is valid. Most data validation is very simple and doesn't require much effort.

Even when data comes from an XHTML form control that is restricted to specific values, we must still validate the data.

There is one form of PHP code injection that we don't need to worry about. By default Joomla! always disables 'register globals'. In scripts where 'register globals' is enabled, all URI query values are automatically converted into variables, literally injecting variables into a script.

Imagine we are using an input value to determine which class to instantiate. If we do not sanitize the incoming data, we run the risk of instantiating a class that could be used to malicious effect. To overcome this we could use a predefined list of class names to ensure the data is valid:

// define allowed classes
$allow = array('Monkey', 'Elephant', 'Lion');
// get the class name
$class = JRequest::getWord('class', 'Monkey', 'GET');
$class = ucfirst(strtolower($class));

Notice that we use the getWord() method to retrieve the value; this ensures that the value only includes letters and underscores. We also modify the case of the value so as to ensure it is in the same format as the expected value. Once we have defined the expectable class names and retrieved the value we can validate the value:

if(!in_array($class, $allow))
{
// unknown class, use default
$class = 'Monkey';
}

Imagine we want to execute a shell command. This type of process is potentially very risky; some unwanted malicious commands such as rm or del could potentially reduce our server to a gibbering wreck. In this example we define an array of acceptable commands and use the PHP escapeshellarg() function to escape any arguments passed to the command.

$allowCmds = array('mysqld', 'apachectl');
$cmd = JRequest::getVar('cmd', false, 'GET', 'WORD');
$arg = JRequest::getVar('arg', false, 'GET', 'WORD');
if( $cmd !== false && !in_array($cmd, $allow) )
{
$cmd .= ' '.escapeshellarg( $arg );
system( $cmd );
}

Using the correct escape mechanism for the system we are accessing is imperative in preventing code injection attacks.

SQL Injection

Probably one of the most publicized vulnerabilities in PHP applications, SQL injection is potentially fatal. It is caused by inadequate processing of data before database queries are executed.

Joomla! provides us with the JDatabase methods getEscaped() and Quote() specifically for avoiding SQL injection. Consider the following value a' OR name IS NOT NULL OR name='b. If we used this value without escaping the value, we could inadvertently give an attacker access to all the records in a table:

SELECT * FROM `#__test` WHERE `name`='a' OR name IS NOT NULL OR
name='b'

We can overcome this using the Quote() method:

$db =& JFactory::getDBO();
$name = $db->QuotegetEscaped(JRequest('name'));

Using the getEscaped() method escapes any special characters in the passed string. In our example the inverted comas will be escaped by prefixing them with a backslash. Our query now becomes:

SELECT * FROM `#__test` WHERE `name`='a' OR name IS NOT NULL OR
name='b'

The Quote() method is identical to the getEscaped() method except that it also adds quotation marks around the value. Generally we should use Quote() in preference to getEscaped(), because this method guarantees that we are using the correct quotation marks for the database server that is being used.

Something else that we can verify is the number of results returned after we submit a query. For example, if we know that we should only get one record from a query, we can easily verify this.

$db->setQuery($query);
$row = $db->loadAssoc();
if( $db->getNumRows() !== 1 )
{
// handle unexpected query result
}

XSS (Cross Site Scripting)

XSS is the use of scripts that are executed client side that take advantage of the user's local rights. These attacks normally take the form of JavaScript. Another, slightly less common, form of XSS attack uses specially crafted images that execute code on the client; a good example of this is a Microsoft security flaw that was reported in 2004 (http://www.microsoft.com/technet/security/bulletin/MS04-028.mspx).

When we use JRequest::getVar() we automatically strip out XSS code, unless we use the JREQUEST_ALLOWRAW mask. We generally use this mask when dealing with large text fields that use are rendered using an editor; if we do not, valuable XHTML formatting data will be lost.

When we use the JREQUEST_ALLOWRAW mask we need to think carefully about how we process the data. When rendering the data remember to use the PHP htmlspecialchars() function or the static JOutput class to make the data safe for rendering in an XHTML page. When using the data with the database, remember to escape the data using the database object's Quote() method.

If you want to allow your users to submit formatted data, you may want to consider using BBCode (Bulletin Board Code). BBCode is a simple markup language that uses a similar format to XHTML. Commonly used on forums, the language allows us to give the user the power to format their data without the worry of XSS. There are all sorts of BBCode tags; exactly how they are rendered may differ.

BBCode

XHTML

Example

[b]Bold text[/b]

<b>Bold text</b>

Bold text

[i]Italic text[/i]

<i>Italic text</i>

Italic text

[u]Underlined text[/u]

<u>Underlined text</u>

Underlined text

:)

<img src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="/somewhere/smile.jpg" />

[quote]Some quote[/quote]

<div class="quote">Some quote</div>

Some quote

Joomla! does not include any BBCode-parsing libraries. Instead we must either build our own parser or include an existing library. One such BBCode library is a class available from http://www.phpclasses.org/browse/package/951.html created by Leif K-Brooks and released under the PHP License. This class gives us lots of control; it allows us to define our own BBCode tags, use HTML entity encoded data, and import and export settings.

When we use BBCode, or a similar parsing mechanism, it is important that if we intend to allow the data to be editable, we store the data in its RAW state.

File System Snooping

A common error when working with files is to allow traversal of the file system. Joomla! provides us with a number of classes for dealing with the file system. This example imports the joomla.filesystem library and builds a path based on the value of the CGI request file (the path must not be relative).

jimport('joomla.filesystem');
$path = JPATH_COMPONENT.DS.'files'.DS
.JRequest('file', 'somefile.php', 'GET', 'WORD');
JPath::check($path);

When we use the JPath::check() method, if $path is considered to be snooping, an error will be raised and the application will be terminated. Snooping paths are identified as paths that do not start with JPATH_BASE and do not attempt to traverse the tree using the parent directory indicator .. (two periods).

Other classes in the joomla.filesystem library include JFile, JFolder, and JArchive. It's important to realize that none of these classes validate path parameters to prevent snooping. This is because there are times when we expect a path to be classified as snooping.

Mastering Joomla! 1.5 Extension and Framework Development The Professional Guide to Programming Joomla!
Published: November 2007
eBook Price: $26.99
Book Price: $49.99
See more
Select your format and quantity:

Dealing with Attacks

Parsing input is only one part of security handling. Another part is the evasive action that an extension can automatically take if an attack is detected. Here are three good ways of dealing with detected attacks; they could be used separately or in conjunction with one another:

  1. Log the user out, possibly blocking their account.
  2. Maintain a log file of detected attacks.
  3. Email the site administrator and inform them of the attack.

Log Out and Block

If the attack has come from a logged in user we can end the user's session and optionally block them from logging in until an administrator unblocks their account. Logging out a user and blocking them may not be appropriate. An instance appearing to be an attack could be a genuine mistake on the part of the user or a misclassification. We could use a 'three strikes and you're out' approach. This way we can reduce the chance of irritating genuine users but maintain a high level of security.

One way of implementing this would be to build a Plugin, an event handler class (extends JPlugin) registered to the application. This modular approach to dealing with attacks, would allow us to reuse the plugin throughout our extensions. The UML diagram shows one design we could use.

joomla

_params is a temporary store for the Plugin parameters (JParameter object). onAttackDetected() is the method that will be executed when an attack is detected. &_getParams() gets the Plugin parameters (uses _params). _attackCount() gets the number of detected attacks so far (stored in the session). _incrementAttacks() increments the number of attacks and returns the new number of attacks. When the user exceeds the maximum number of detected attacks _actionLogout() and _actionBlock() are run, if they are enabled in the Plugin parameters.

This is the definition of the parameters; this would be in the plugin XML file.

<params>
<param name="sessionValue" type="text" size="20"
default="detectedAttacks" label="sessionValue"
description="Name of session value to store attack
counter in." />
<param name="maxAttacks" type="text" size="2" default="3"
label="maxAttacks" description="Maximum number of
detections per session." />
<param name="@spacer" type="spacer" default="" label=""
description="" />
<param name="logout" type="radio" default="1" label="logout"
description="Logout user.">
<option value="0">Off</option>
<option value="1">On</option>
</param>
<param name="block" type="radio" default="1" label="block"
description="Block user.">
<option value="0">Off</option>
<option value="1">On</option>
</param>
</params>

The example shows how we could implement the _logout() method. Notice we check if the user is logged in before attempting to log them out.

/**
* Logs the current user out.
*
* @access private
* @return boolean true on success
*/
function _actionLogout()
{
global $mainframe;
$user =& JFactory::getUser();
if($user->get('id') && $mainframe->logout() )
{
return true;
}
return false;
}

The next example shows how we could implement the _block() method. Notice we check if the user is logged in before attempting to block them.

/**
* If they are logged in, blocks the current user's account.
*
* @access private
* @return boolean true on success
*/
function _block()
{
$user =& JFactory::getUser();
print_r($user);
if($user->get('id'))
{
$user->set('block', '1');
return $user->save(true);
}
return false;
}

To be able to use the DefenceHandler class we need to register the event with the application. This creates a new instance of DefenceHandler and attaches it to the application event handler.

$mainframe->registerEvent('onAttackDetected',
'DefenceHandler');

If we detected an attack we would use the handler by triggering the event onAttackDetected in the application ($mainframe):

$mainframe->triggerEvent('onAttackDetected');

Attack Logging

Detecting attacks can prevent individual attacks but, when we encounter a persistent attacker, having a history of attacks can provide us with vital information. This information can be used to determine the nature of each attack and to try to identify the perpetrator.

Building on our previous example we can use the JLog class to build up a history of attacks. Here's an example of how we might implement the _actionLog() method in our DefenceHandler class.

/**
* Logs an Attack.
*
* @access private
* @return boolean true on success
*/
function _actionLog()
{
$user =& JFactory::getUser();
$uri =& JFactory::getURI();
$options = array('format'=>"{DATE}t{TIME}t{CIP}
t{USER}t{STRIKE}t{REQUEST}");
$log =& JLog::getInstance($extension.'.Defences.log',
$options);
$entry = array(
'REQUEST' => $uri->toString(),
'USER' => $user->get('id'),
'STRIKE' => $this->strikeCount()
);
$log->addEntry($entry);
}

To use this we would need to modify the plugin XML file to include the option to log attacks and we would need to update the onAttackDetected() method to deal with logging.

Notify the Site Administrator

We may also want to notify the site administrator when a user exceeds the maximum number of attacks. This time we need to add a _actionNotify() method to our DefenceHandler class and a text field for an email address in our plugin's XML file parameters.

/**
* Logs an Attack.
*
* @access private
* @param string email address
* @return boolean true on success
*/
function _actionNotify( $email )
{
global $mainframe;
$mailer =& $mainframe->getMailer();
$mailer->setSender($email);
$mailer->setRecipient($email);
$mailer->setSubject(JText::_('Excessive Attacks Detected'));
$mailer->setBody(JText::_"A user has exceeded the number of
allowed attacks. Please consult your
error log for more details."));
$mailer->Send();
}

This example is relatively simple. We could develop the method further by adding a more comprehensive subject line and body. If logging is enabled we could also include a copy of the log as an attachment (we would have to be careful if the log file was very large).

Summary

Attackers are very resourceful and will go to great lengths to discover and exploit security flaws. Remember to always sanitize incoming data and escape outgoing data. Joomla! and PHP provide us with a plethora of utilities that, if used correctly, can ensure that our extensions are as secure as possible.

Mastering Joomla! 1.5 Extension and Framework Development The Professional Guide to Programming Joomla!
Published: November 2007
eBook Price: $26.99
Book Price: $49.99
See more
Select your format and quantity:

About the Author :


James Kennard

James Kennard is a computer programmer. He has worked with various PHP and MySQL applications, since 2002. He quickly discovered Mambo/Joomla! because of its flexible extension manager. James currently maintains one open-source Joomla! component, which has been translated into over fifteen languages. Moreover, he has plans to build two more open-source components. Examples of his work can be found on his personal website www.webamoeba.co.uk.

Books From Packt


Joomla! 1.5: Beginner's Guide
Joomla! 1.5: Beginner's Guide

MediaWiki 1.1 Beginner's Guide
MediaWiki 1.1 Beginner's Guide

CMS Made Simple 1.6: Beginner's Guide
CMS Made Simple 1.6: Beginner's Guide

Getting started with Audacity 1.3
Getting started with Audacity 1.3

Joomla! 1.5 Multimedia
Joomla! 1.5 Multimedia

Joomla! with Flash
Joomla! with Flash

Apache MyFaces 1.2 Web Application Development
Apache MyFaces 1.2 Web Application Development

Drupal 6 Attachment Views
Drupal 6 Attachment Views


Your rating: None Average: 5 (1 vote)

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
h
E
z
Q
e
x
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software