Top Left Text cha

Web & App Development

Secure integers and the rest of numeric values

With the MySQL database, numeric fields should not be quoted, so it is important that they be typecast instead. Failure to do this will leave your code vulnerable to an attacker inserting a string containing SQL data.

Depending on the type, numeric types are cast like this:

$query = 'SELECT * FROM #__table WHERE `id`=' . (int) $id;
// For SQL data types: FLOAT, DOUBLE
$query = 'SELECT * FROM #__table WHERE `id`=' . (float) $id;

Secure strings

In the examples that follow it is assumed that $db is an instance of a Joomla database object. This can always be obtained from JFactory using

$db = JFactory::getDBO();

Strings should always be escaped before being used in an SQL statement. This is actually very simple as the JDatabase->quote method escapes everything for you. You can also use the JDatabase->escape method directly. The following statements are equivalent:

$query = 'SELECT * FROM #__table WHERE `field` = ' . $db->quote( $db->escape( $field ), false );
$query = 'SELECT * FROM #__table WHERE `field` = ' . $db->quote( $field );

Secure on search

Special attention should be paid to LIKE clauses which contain the % wildcard character as these require special escaping in order to avoid possible denial of service attacks. LIKE clauses can be handled like this:

// Construct the search term by escaping the user-supplied string and, if required, adding the % wildcard characters manually.
$search = '%' . $db->escape( $search, true ) . '%' );
// Construct the SQL query, being careful to suppress the default behaviour of Quote so as to prevent double-escaping.
$query = 'SELECT * FROM #__table WHERE `field` LIKE ' . $db->quote( $search, false );

Secure dates

If data is to be entered into a datetime column then you can use the Joomla API to ensure a valid date format:

$date = JFactory::getDate( $mydate );
$query = 'UPDATE #__table SET `date` = ' . $db->quote( $date->toMySQL(), false );

Note that it is necessary to suppress database escaping as legitimate dates may contain characters that should not be escaped.

Secure field names

In the comparatively rare case where a field name is a variable, that should also be quoted using an API call:

$query = 'SELECT * FROM #__table WHERE ' . $db->quoteName( $field-name ) . '=' . $db->quote( $field-value );

Secure arrays of integers

When you have an array of ids, typically used for IN() queries, you have to sanitise it also with JArrayHelper::toInteger($cid); before imploding:

$query->where($db->quoteName('x.category_id') . ' IN (' . implode(',', $catId) . ')');

Short aliases of Quote and QuoteName

Shorter alternatives to the quote methods may also be used. The following statements are equivalent:

$query = 'SELECT * FROM #__table WHERE ' . $db->quoteName( $field-name ) . '=' . $db->quote( $field-value );
$query = 'SELECT * FROM #__table WHERE ' . $db->qn( $field-name ) . '=' . $db->q( $field-value );

Securing forms

Apart from cleaning input variables as described above, you can also implement a simple technique which makes it more difficult for a cross-site request forgery attack (CSRF) to succeed. This involves adding a randomly-generated unique token to the form which is checked against a copy of the token held in the user's session. By checking that the submitted token matches the one contained in the stored session, it is possible to tie a rendered form to the request variables presented.

In POST forms you should add a hidden token field using:

echo JHTML::_( 'form.token' );

This outputs the token as a hidden form field looking like this:

<input type="hidden" name="8cb24ae69ffd7828ccecbcf06056e6fc" value="1" />

and places a copy of the token into the user's session, for later checking.

If you need to add the token to a URL rather than a form then you can use something like this:

echo JRoute::_( 'index.php?option=com_mycomponent&' . JSession::getFormToken() . '=1' );

In the most common scenario, you will want to check the token following a POST to the form handler. This can be done by adding this line of code to form handler:

JRequest::checkToken() or die( JText::_( 'Invalid Token' ) );

If you need to pass the token in a GET request then you can check it like this:

JRequest::checkToken( 'get' ) or die( JText::_( 'Invalid Token' ) );

In both cases the code will die if the token is omitted from the request, or the submitted token does not match the session token. If the token is correct but has expired, then JRequest::checkToken will automatically redirect to the site front page.

Cleaning filesystem paths

If there is any possibility that a filesystem path might be constructed using data that originated from user input, then the path must be cleaned and checked before being used. This can be done quite simply like this:

JPath::check( $path );

This will raise an error and terminate Joomla if the path contains a ".." or leads to a location outside the Joomla root directory. If you want to deal with the error yourself without terminating the application, then you can use code like this:

$path = JPath::clean( $path );
if (strpos( $path, JPath::clean( JPATH_ROOT ) ) !== 0) {
    // Handle the error here.

The JPath:clean method can be used in your own code too. It merely removes leading and trailing whitespace and replace double slashes and backslashes with the standard directory separator.

Cleaning filesystem file names

As with filesystem paths, if there is any possibility that a file name might be constructed using user-originated data, then the file name must be cleaned and checked before use. This can be done like this:

$clean = JFile::makeSafe( $unclean );

This method removes sequences of two or more "." characters and any character that is not alphabetic, numeric or a dot, dash or underscore character. If there is a leading dot then that is removed too.

  • No comments found

Leave your comments

Post comment as a guest

Your comments are subjected to administrator's moderation.