Secure PHP programming

Lecture



This lesson is intended more for those who have either read previous lessons and know the basics, or already knew. Yes, yes, it's about safe programming. To clarify, safe programming does not mean that if you write something wrong, then the script writer can for no reason get a magic pendel from his creation, when security is not observed. And it also does not mean that the program can explode with the power of a good grenade.
No, no, safe programming means creating such a program that will work correctly in the most extreme situations, creating maximum security, firstly, for user data, and secondly, for the system that executes it.
Why did I put the data in the first place? Yes, because in the case of "X" (that is, when an abnormal situation occurred), if the damage was caused to the system, then this is the cost of repairing only the system. And imagine that this is our banking operations and something was stolen or damaged? Here we will have to remember about the grenade and Pendel.


About how to
Well, with the introduction it seems to have figured out, let's get down to business. What does each program work with? Of course, with the data. Data is received, data is transmitted, data is processed, they are searched for, and so on. And at every stage you need to think about security. That is how it is. You can not first write the script somehow, and then proceed to the phase of its "disinfection". It will not work out - we are all people, and we will definitely forget something. And then, if everything is done right at once, then there will be no doubt later. And, therefore, the need to recheck. Although, of course, there are no programs without errors. But we can make it so that their number is minimal.

About users and hackers

Now I would like to tell you about why we should make our program safe. After all, if users are interested in the safety of their data, why would they harm the system? .. So, not all users are interested in data safety. Or rather, there are those who are interested in not keeping other people's data safe. Again - credit card numbers. How do you want to steal it. So, if we have such figures, then I insist: from the point of view of the system, any user === hacker. That is, summing up the paragraph, I will say: the presumption of guilt acts in relation to all user actions.


Targets and loopholes

Now about the specifics. I will tell about the most frequent errors in programs. The actions of hackers, who hope that the author did not take into account something, are aimed at them. Using such errors, you can pick up loopholes, and use them. So let's go.
Example. We have an authorization script - the most frequent case. Let it look like this:

<?PHP
$admin=0;
//тут может быть еще что-нибудь предварительное
$admin=$_REQUEST['admin'];
if($admin)
{
//..функционал админа
}
else
{
//что-то еще
}
?>

What would seem to be wrong here? If the user is an admin, we show him part of the administration, otherwise, no. But on closer examination, you can notice a serious mistake. If you call the script like this:

CODE:

script.php? admin = 1

That anyone will see part of the administrator. After all, $ admin will come from a request to the script and will be pre-installed. This is a classic "register_globals = On" + "uninitialized variable" error. Indeed, because we did not initialize the $ admin variable, that’s the result.
The best solution is to disable register_globals and explicit initialization of all variables used in the script.

Let's move on to the next example. Let our system be some kind of process monitoring. But this is not just a monitor of a process, but a universal monitor (that is, we want to make a system that knows how to monitor the state of any process). You can easily sketch:

<?PHP
$rgResult=array();
$processName=$_POST['processName'];
exec("ps aux | grep ".$processName, $rgResult);
foreach($rgResult as $value)
{
echo($value."<br>\n");
}
?>

Simply put, we display all the found information about the script we are interested in. Well, remember the security. In this example, a gross error is visible - the transfer of user data directly to execution. In what place (we like execute only the ps command)?
In the very place where we just pass the name of the process. After all, we can write in $ processName, say:

CODE:

php && cat / etc / passwd

This will first search for information about running php scripts (in the shell) - most likely, the expected input, and then perform the output of the system file information - it does not come out weakly. The only amendment - modern UNIX - systems (like Linux, FreeBSD for example) are quite stable even in the case of such "curved" scripts. Most likely, the OS itself will not allow the script to read the contents of this file. But you should not hope for a system, you need to prevent such attempts at the script level. In this case, how? Just set the list of allowed processes:

<?PHP
$rgAllowedProcess=array("smbd", "nmbd", "httpd");
$rgResult=array();
$processName=$_POST['processName'];
if(in_array($processName, $rgAllowedProcess))
{
exec("ps aux | grep ".$processName, $rgResult);
foreach($rgResult as $value)
{
echo($value."<br>\n");
}
}
?>

And that's it. On the user side, you can provide, for example, a drop-down list with the names of the allowed processes.

I will also give the third common example of unsafe code. Again, let us have an authentication script:

<?PHP
$login=$_POST['login'];
$password=$_POST['password'];
//предполагаем соединение с БД установленным
$result=mysql_query("SELECT user_id FROM users WHERE login=$login AND password=$password");
if(mysql_num_rows($result))
{
//все хорошо - пользователь найден, выполняем процедуру его логина
}
else
{
//какая-то ошибка для пользователя
}
?>

This is a classic example of the so-called SQL-Injection. More precisely. not himself, but opportunities for him. After all, let's imagine that we’ll pass this to the $ password field:

CODE:

12345; UPDATE users SET password = '0' WHERE login = 'admin'

What will come out? That's right, MySQL will receive a request (the connection has already been established) and will perform a request to update the password of the admin user. After that, we log in with this user with the password '0' and we can consider the task as completed.
For protection, user input must be escaped . This means that all special characters are preceded by a special "\" character or replaced. For this there are functions:
mysql-real-escape-string
For the library itself mysql; mysqli-real-escape-string for the mysql library; and addslashes for the general case.

Almost always the first is preferable, but sometimes the second can be useful (when you want to screen not all, for example, for an advanced user search). I personally use the second one in systems that are focused on deliberately bona fide users (yes, there are some) - for example, some kind of administration system for working in a narrow circle of developers of a certain project. But vigilance is still not worth losing in such cases.


Home defense

There are situations when even a well-written script still leads to hacking. This can happen if the system itself is configured incorrectly. This can be an OS or a web server. Or a database server.
Again, an example:
We have 2 files:

/www
|
+---database.inc
|
+---script.php

And script.php, let's say, looks like this:

<?PHP
include("database.inc");
//далее работа с БД
?>

Actually, database.inc is needed to connect to the database. It would seem that everything is good and convenient, it is not necessary to write the database connection strings several times in the scripts. But again, a smart user enters http: //our_site/database.inc
And what? Nothing good. The user simply displays this file, and that's it. Just because the web server does not know this type of file (in most cases) and offers to download it. Well, knowing the user and the password to the database you can do a lot of things.

How to protect yourself? First, do not use unintelligible extensions for include files. Connect simply * .php, and that's it. Secondly, lay out all the files that are not meant for viewing in a directory that is simply not accessible to the web server. For example, in a directory that is higher in the directory tree than the root of the web server.
Sometimes it is advised to use .htaccess files to deny access to such files. But I am sure - why do this if we have a universal solution? I would call a solution with .htaccess rather a consequence, a solution to an invented problem. I strongly doubt that without any tricky * .inc there is indispensable.

Further - an example for a DB. Here, security problems most often occur when the database user on whose behalf the script runs has too many rights. Rule number 1 - never work in a script on behalf of the DB user root . No need to do so, and that's it. This user is not intended to work from a script. Exceptions are too rare to do so.

Otherwise, I would recommend for each project to create their own database, for this database - the user of the same name and to give this user full rights (but without the GRANT right) to this database. There may be exceptions when several users must work with the same database.

Then the rights should be handed out as follows - first select all rights , and then, as necessary, issue them. Then the set of rights will be strictly minimal. Then I’ll add that all users should have the right of only a local login (in other words, users with a host field equal to "%" in the service table should be absent if possible). If there is a need for a remote login, then it is better to add each host separately, avoiding the notorious host "%"

Now an important component is the system itself. It means the operating system. I already mentioned that UNIX systems are very robust when it comes to security. But if you do not think, you can break the wood in such systems. I would formulate the rules as follows:
- For each service (web server, database server, all kinds of front-end, accelerators, etc.) we create a separate user, all have one group (for example, daemon). Permission is granted only to those files that should actually be executed (and not just chmod -R 755). Rights "7" - full rights, it is worth issuing only to those directories / files that can not have other permissions. As an example, a directory where we take files from users (although in itself such a directory is a potential breach, think about why).
- Use chroot for system root directory. This is necessary in case of hacking - then the hacker will get access only to the web part of our server, and not to all of it.
- Log the scripts themselves all unusual user actions. In other words, if everything was done correctly, and an attempt (no matter accidental or malicious) was hacked, the administrator should be notified. It is desirable so that nothing is displayed to the user.
- All php error messages should be disabled . After all, knowing the errors, the hacker can learn the structure of the system from them. And it facilitates the task of hacking. To test the system, however, I highly recommend with all the errors included. The ideal situation is that the program is brought to a state where, even with all the errors included, it does not output even Notice in any cases. But even in this case, you need to disable error output when the program is provided to users.

Vulnerabilities of this type can be encountered at hosting providers that are not too concerned about security. And most likely, you will not be allowed to fix it, since you will not be the system administrator. What to do then? Change the host. Simple and clear.


Comments


To leave a comment
If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

Running server side scripts using PHP as an example (LAMP)

Terms: Running server side scripts using PHP as an example (LAMP)