Preventing Attacks on Joomla! 1.5 Websites

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:

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.

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:

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:

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.

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'

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.

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="/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).

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.

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:

Log the user out, possibly blocking their account.

Maintain a log file of detected attacks.

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.

_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.

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.

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.

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.

Alerts & Offers

Series & Level

We understand your time is important. Uniquely amongst the major publishers, we seek to develop and publish the broadest range of learning and information products on each technology. Every Packt product delivers a specific learning pathway, broadly defined by the Series type. This structured approach enables you to select the pathway which best suits your knowledge level, learning style and task objectives.

Learning

As a new user, these step-by-step tutorial guides will give you all the practical skills necessary to become competent and efficient.

Beginner's Guide

Friendly, informal tutorials that provide a practical introduction using examples, activities, and challenges.

Essentials

Fast paced, concentrated introductions showing the quickest way to put the tool to work in the real world.

Cookbook

A collection of practical self-contained recipes that all users of the technology will find useful for building more powerful and reliable systems.

Blueprints

Guides you through the most common types of project you'll encounter, giving you end-to-end guidance on how to build your specific solution quickly and reliably.

Mastering

Take your skills to the next level with advanced tutorials that will give you confidence to master the tool's most powerful features.

Starting

Accessible to readers adopting the topic, these titles get you into the tool or technology so that you can become an effective user.

Progressing

Building on core skills you already have, these titles share solutions and expertise so you become a highly productive power user.