Using COM applyFilter
Contents
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 article explains how to use COM_applyFilter and also provides additional information on how to make your scripts more secure.
Why parameter filtering?
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!
COM_applyFilter
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 ($_POST['myparameter']);
Or, in case, of a parameter that is supposed to be numeric:
$myvalue = COM_applyFilter ($_POST['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.
A word on register_globals
As can be seen in the examples above, it is recommended NOT to rely on register_globals being "on" (Geeklog itself doesn't require it any more as of Geeklog 1.4.0) but to use the global $_GET and $_POST arrays instead.
Note: The $_GET, $_POST, and $_REQUEST arrays are only available as of PHP 4.1.0, but that has been the minimum requirement for Geeklog for some time now.
See also Use $_GET, $_POST and $_REQUEST
A bad example
If possible, you should not follow Geeklog's example of testing whether a parameter is set in the $_GET or $_POST 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 $_GET array (because you are expecting to be called through an HTTP GET request), don't bother checking the $_POST 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.
When not to use COM_applyFilter
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 ($_POST['mytext']); // do something with it, then: $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.
Preparing for database storage
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.
Safely identifying the current user
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 }
Use typesafe comparison operations
The content of the superglobal arrays ($_GET, $_POST, $_REQUEST etc) are all strings, as are any variables created by register_globals. As this is the case, you can secure your code further by using typesafe comparisons:
if ($authorized === TRUE) { // Only matches if $authorized contains an actual boolean true value. }
Summary
- use COM_applyFilter on any parameters passed through an HTTP GET or POST request
- 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 $_POST and $_GET instead
- write your script such that you know whether your parameters are in $_POST or $_GET
- 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