[geeklog-devel] How to use COM_applyFilter

Dirk Haun dirk at haun-online.de
Thu Feb 26 13:11:51 EST 2004

I wrote this little piece to explain the use of COM_applyFilter. It's
mainly aimed at authors of plugins and other add-ons, but most of it
applies to new code that's supposed to go into Geeklog as well. Comments
welcome (as well as suggestions on where to post it so that it can easily
be found ...).

bye, Dirk

--- snip ---

Abstract: Geeklog 1.3.9 introduced a new function, COM_applyFilter, that
is used to filter parameters passed in HTTP GET and POST requests. It is
strongly suggested that plugins and other add-ons make use of this function.
This post explains how to use COM_applyFilter and also provides additional
information on how to make your scripts more secure.

Whenever parameters are passed in an HTTP GET request (usually in a URL
of the form script.php?parameter=value) or an HTTP POST request (usually
from an input field in a form, e.g. <input name="parameter" value="value">)
there is a potential risk that these parameters are manipulated. With GET
requests, it is easy to edit the URL and manipulated POST requests can be
sent through manipulated forms or by using tools like netcat.

It is therefore important not to trust these parameters too much!

The COM_applyFilter function was designed to clear parameters from the
most commonly used injection attempts (both SQL and JavaScript injections).
So, to strip any potentially malicious content from parameters, use
COM_applyFilter as follows:

    $myvalue = COM_applyFilter ($HTTP_POST_VARS['myparameter']);

Or, in case, of a parameter that is supposed to be numeric:

    $myvalue = COM_applyFilter ($HTTP_POST_VARS['myparameter'], true);

Your script should be prepared to handle the case that $myparameter is empty
(or 0, for numerical parameters) after the call to COM_applyFilter. This will
usually be the case when content was stripped from the parameter (unless it
was empty / zero to begin with). Whether your script aborts in those cases
or continues with default values instead of the empty / zeroed parameter,
is up to you. Both may make sense, depending on the circumstances.

As can be seen in the examples above, it is recommended NOT to rely on
register_globals being "on" (although Geeklog still requires this) but
to use the global $HTTP_GET_VARS and $HTTP_POST_VARS arrays instead (don't
forget to declare them as "global" when you're using them inside a function).
The $_GET, $_POST, and $_REQUEST arrays could be used instead of
and $HTTP_POST_VARS, but since they were only introduced in PHP 4.2.0,
you may 
restrict the audience for your plugin / add-on somewhat, as quite a few
Geeklog installs out there are still running on older versions of PHP.

If possible, you should NOT follow Geeklog's example of testing whether a
parameter is set in the $HTTP_GET_VARS or $HTTP_POST_VARS array. Instead,
write your code such that at any moment you know exactly where your parameters
would be in case of proper execution of the script. So if you know that at
a specific point in your script, parameters can only be in the $HTTP_GET_VARS
array (because you are expecting to be called through an HTTP GET request),
don't bother checking the $HTTP_POST_VARS array (instead, simply ignore it).
Geeklog's core code contains a few bad examples where at specific points in
a script it is not clear whether we came there through a GET or a POST
request and thus have to test both for the proper parameters. Depending on
the situation, it may make things easier for an attacker and the code is in
general much harder to maintain. Don't repeat that mistake.

Please note that you can NOT use COM_applyFilter on any sort of "free-
form" content, such as the text of a story or things like a user's full
name, since the function would strip out many special characters (such as
quotes) and make the content illegible and / or useless. Instead, you
should do something like this:

    $mytext = COM_stripslashes ($HTTP_POST_VARS['mytext']);
    // do something with it
    $mytext = addslashes ($mytext);
    DB_save ($_TABLES['mytable'], "mytext", '$mytext');

The COM_stripslashes function will strip any slashes that may have been added
during the POST operation, if the PHP option magic_quotes_qpc is "on" (and
leaves the text untouched, if it is off), thus ensuring that you get the text
back exactly as it was entered by the user. You can then process the text
as needed by your plugin / add-on.

Before you store the text in the database, you should call addslashes on it
to ensure that any special characters are properly escaped. This will NOT
add slashes to the content in the database, it will only ensure that the
text is properly stored (and in case it contains any SQL injection attempts,
those would be stored as text, too, instead of being executed as part of
the save operation).

Actually, it may be a good idea to apply addslashes on ALL parameters that
go into the database, even if they have been passed through COM_applyFilter
before, just in case.

On a side note, if you need to identify the current user, you should NEVER
rely on the user's id passed through GET or POST requests (e.g. by embedding
it in a form and reading it back when the form was submitted). Instead,
ALWAYS use the global variable $_USER['uid']. This variable may be empty
or contain 1, which indicates an anonymous user, i.e. a user that is not
logged in. So you should use something like

    if (!empty ($_USER['uid']) && ($_USER['uid'] > 1)) {
        // this is a logged-in user
    } else {
        // this is an anonymous user

To summarize:

- use COM_applyFilter on any parameters passed through an HTTP GET or POST
- add "true" to the call when the parameter is supposed to be numeric
- be prepared for the parameter to be empty or zero afterwards
- don't rely on register_globals - use $HTTP_POST_VARS and $HTTP_GETS_VARS
- write your script such that you know whether your parameters are in
- for "free-form" content, don't use COM_applyFilter but be careful to filter
  it otherwise and apply addslashes before storing it in the database
- always rely on $_USER['uid'] to identify a user


More information about the geeklog-devel mailing list