The material is intended mainly for novice web programmers.
Introduction
I am often approached by clients who have self-written CMS installed or modules written by novice web programmers who do not understand what is needed to protect data and often copy filtering functions without thinking about how they work and what they need to do with them.
Here I will try to describe as often as possible frequent errors when filtering data in a PHP script and give simple tips on how to properly perform data filtering.
')
There are many articles on the network about data filtering, but they are not properly complete and without detailed examples.
Debriefing.
Filtration. Error number 1
For numeric variables, this check is used:
$number = $_GET['input_number']; if (intval($number)) { ... SQL ... }
Why does it lead to SQL injection? The fact is that the user can specify the value in the variable
input_number :
1'+UNION+SELECT
In such cases, the test will be successfully passed, because the
intval function gets the integer value of the variable, i.e. 1, but nothing has changed in the
$ number variable itself, so all the malicious code will be passed to the SQL query.
Proper filtering:
$number = intval($_GET['input_number']); if ($number) { ... SQL ... }
Of course, the condition may change, for example, if you need to get only a certain range:
if ($number >= 32 AND $number <= 65)
If you use checkboxes or multi-selects with numeric values, run this check:
$checkbox_arr = array_map('intval', $_POST['checkbox']);
array_mapI also meet the filtering in the form:
$number = htmlspecialchars(intval($_GET['input_number']));
htmlspecialcharsOr:
$number = mysql_escape_string(intval($_GET['input_number']));
mysql_escape_stringNothing but a smile, this can not cause :)
Filtration. Error number 2.
For string variables, the following filtering is used:
$input_text = addslashes($_GET['input_text']);
The
addslashes function screens specials. characters, but it does not take into account the coding of the database and filtering can be bypassed. I will not copy the text of the author who described this vulnerability and give you just a link to
Chris Shiflett (you can search for translation in Runet).
Use the
mysql_escape_string or
mysql_real_escape_string function , for example:
$input_text = mysql_escape_string($_GET['input_text']);
If you do not intend the occurrence of html tags, then it is best to do this filtering:
$input_text = strip_tags($_GET['input_text']); $input_text = htmlspecialchars($input_text); $input_text = mysql_escape_string($input_text);
strip_tags - removes html tags.
htmlspecialchars - converts specials. characters in html entity.
So you protect yourself from XSS attacks, in addition to SQL injection.
If you need html tags, but only as for outputting source code, it is enough to use:
$input_text = htmlspecialchars($_GET['input_text']); $input_text = mysql_escape_string($input_text);
If it is important for you that the value of a variable is not empty, then use the
trim function, an example:
$input_text = trim($_GET['input_text']); $input_text = htmlspecialchars($input_text); $input_text = mysql_escape_string($input_text);
Filtration. Error number 3.
It concerns the search in the database.
To search by numbers, use the filtering described in the first error.
To search the text, use the filtering described in the second error, but with reservations.
In order for the user to fail to perform a logical error, you need to delete or screen the spec. SQL characters.
An example without. line processing:
$input_text = htmlspecialchars($_GET['input_text']);
At the exit, we get a request of the form:
... WHERE text_row LIKE '%".$input_text."%' ...
This will significantly increase the load on the base.
In my script, I use a function that removes unwanted characters from the search:
function strip_data($text) { $quotes = array ("\x27", "\x22", "\x60", "\t", "\n", "\r", "*", "%", "<", ">", "?", "!" ); $goodquotes = array ("-", "+", "#" ); $repquotes = array ("\-", "\+", "\#" ); $text = trim( strip_tags( $text ) ); $text = str_replace( $quotes, '', $text ); $text = str_replace( $goodquotes, $repquotes, $text ); $text = ereg_replace(" +", " ", $text); return $text; }
Of course, not all of the above characters are dangerous, but in my case they are not needed, so I search and replace.
Filtering example:
$input_text = strip_data($_GET['input_text']); $input_text = htmlspecialchars($input_text); $input_text = mysql_escape_string($input_text);
I also advise you to make a limit on the number of characters in the search, at least not less than 3, because if you have a large number of records in the database, then searching for 1-2 characters will significantly increase the load on the database.
Filtration. Error number 4.
Values in the
$ _COOKIE variable are not filtered. Some people think that since this variable cannot be passed through a form, this is a guarantee of security.
This variable is very easy to fake with any browser by editing the site’s cookies.
For example, in one well-known CMS there was a check used by the site template:
if (@is_dir ( MAIN_DIR . '/template/' . $_COOKIE['skin'] )){ $config['skin'] = $_COOKIE['skin']; } $tpl->dir = MAIN_DIR . '/template/' . $config['skin'];
In this case, you can replace the value of the
$ _COOKIE ['skin'] variable and cause an error, as a result of which you will see the absolute path to the site folder.
If you use the value of cookies to save to the database, then use one of the above described filterings, also applies to the
$ _SERVER variable .
Filtration. Error number 5.
The
register_globals directive is
enabled . Be sure to turn it off if it is on.
In some situations, you can pass the value of a variable that should not have been passed, for example, if there are groups on the site, then group 2 must be empty or equal to 0, but it is enough to forge the form by adding code:
<input type="text" name="group" value="5" />
In a PHP script, the
$ group variable will be equal to 5 if it has not been declared in the script with the default value.
Filtration. Error number 6.
Check the downloadable files.
Check out the following items:
- File extension. It is desirable to prohibit the download of files with extensions: php, php3, php4, php5, etc.
- Is the file uploaded to the server move_uploaded_file
- file size
Check. Error number 1.
I came across cases when for an AJAX request (for example: reputation increase) the user name or his ID (to whom reputation increases) was passed, but PHP itself did not check for the existence of such a user.
For example:
$user_id = intval($_REQUEST['user_id']); ... INSERT INTO REPLOG SET uid = '{$user_id}', plus = '1' ... ... UPDATE Users SET reputation = reputation+1 WHERE user_id = '{$user_id}' ...
It turns out we are creating a record in the database, which is completely useless to us.
Check. Error number 2.
When performing various kinds of actions (adding, editing, deleting) with the data, do not forget to check the user's rights to access this function and additional features (using html tags or the ability to publish material without checking).
It has long been fixed in one module of the forum a similar error, when any user could edit the administration message.
Check. Error number 3.
When using multiple php files, make a simple check.
In the
index.php file (or in any other main file) write such a line before connecting other php files:
define ( 'READFILE', true );
At the beginning of other php files write:
if (! defined ( 'READFILE' )) { exit ( "Error, wrong way to file.<br><a href=\"/\">Go to main</a>." ); }
So you restrict access to files.
Check. Error number 4.
Use hashes for users. This will help prevent a particular function from being invoked by XSS.
An example of creating a hash for users:
$secret_key = md5( strtolower( "http://site.ru/" . $member['name'] . sha1($password) . date( "Ymd" ) ) );
Next, in all important forms, substitute an input with the value of the current user hash:
<input type="hidden" name="secret_key" value="$secret_key" />
During the execution of the script check:
if ($_POST['secret_key'] !== $secret_key) { exit ('Error: secret_key!'); }
Check. Error number 5.
When outputting SQL errors, make a simple restriction on access to information. For example, set the password for the GET variable:
if ($_GET['passsql'] == "password") { ... SQL ... } else { ... , ... }
This will allow to hide information from the hacker that can help him in hacking the site.
Check. Error number 5.
Try not to connect files, getting the names of files from outside.
For example:
if (isset($_GET['file_name'])) { include $_GET['file_name'] .'.php'; }
Use the switch
switch :
switch($_GET['file_name']) { case 'file_1': include 'file_1.php'; break; default: include 'file_0.php'; break; }
In such cases, you prevent the connection of files that you have not provided.
Council
For greater reliability, use one of the ready-made and popular classes for filtering data in order not to miss any malicious characters / data. Also in these classes it is often possible to select a data filter.
UPD: Corrected post. Transferred all the tips about the functions and variables that were in the comments.