
PHP Security Essentials
This material is for beginning programmers.
Why so often I see going to some website something like this:
This is one of the standard PHP errors, which is a) ugly for the user; b) potentially dangerous.
Therefore, they must be intercepted and ordered.
Firstly, the error_reporting function allows us to decide which errors we want to see.
In principle, it’s enough to simply turn off the display of all errors (error_reporting (0)), but we don’t need this, because we want to know about errors.
The constant of all errors is E_ALL.
In the fifth version, the constant E_STRICT appeared, showing strict comments on the code.
Of course, it is desirable to see them, but they are not included in E_ALL, therefore we will use the numerical value error_reporting (8191), which absorbs everything, up to new errors of the sixth version.
Note for the curious: error_reporting (E_ALL | E_STRICT) is not suitable, because then PHP 4 will swear, not knowing what E_STRICT is. There will be no problems with the numerical value.
We add a check for DEBUG - a constant set in the config, and, using set_error_handler , we will catch errors in the already running service. By the way, your error reporter should return true, otherwise PHP will throw a standard error.
Result:
(As for comparing a variable with five parameters, I’m not sure about the choice of method: in_array is prettier and much slower, and the switch case case is faster, but completely ugly. Beauty is a subjective matter ...)
Prior to version 4.2.0, the register_globals directive was enabled in PHP by default.
This led to the fact that many are used to the fact that if there is one in the form, then in the PHP code you can check if ($ username == 'admin') ...
However, this is a potential hole that led to many hacks.
Therefore, POST, GET, COOKIE variables must be accessed through superglobals $ _POST, $ _GET, $ _COOKIE.
To many, this seemed too difficult and the import_request_variables command , returning everything to normal, has become very popular .
So here.
Do not do this.
Another problem with register_globals:
If the user is not an administrator, and the variable $ user_level is not initialized
(it is not assigned a value of 0 at the beginning of the script, in the hope that it is 0 automatically),
then a bad person can add foo.php? User_level = 999 in the address bar and gain access.
So popular among beginners is the design
dangerous. If the user enters the password 'OR` username` =' admin instead of the password, the system will let him in as an administrator.
The given example, of course, is elementary.
But if you do not solve the problem globally, you can always skip any query that is subject to SQL injection.
To combat this, the PHP developers decided to make sure that all the information coming from the user was processed and all the quotes were escaped (they are preceded by a slash, which the addslashes command does ).
What happened? All information from the user comes with slashes. Even the one like slashes should not receive. For example, comments on the article.
Not only that, this is not a 100 percent defense against SQL injection.
Decision.a) with all incoming information, remove slashes, if any. b) We filter all the information received in the SQL query specially for this purpose by the function mysql_real_escape_string (or an analogue for another database).
Remove slashes:
We create a function for filtering (mysql_real_escape_string is long, and tied to the verification format. And if you need to change the filter?)
And use it everywhere. As soon as some dynamic data is sent to SQL, we immediately use quote:
Check everything that the user enters.
By default, he is an attacker.
Try not to filter , try to validate .
In other words, do not create a blacklist, create a white one.
Instead
use
So you will be sure that the information is clean and there will be no surprises.
If you are making a list of forbidden characters, you can always look at some bad% 00 and the like, which you probably don't know about.
Of course, there are situations when filtering is needed, for example, when a user writes a comment.
Then you have to cut off bad characters.
But in principle, you should try to validate.
There are several teams that must be handled very carefully.
These include, require, readfile, eval,,, system, exec, create_function, dir, fopen and the like.
Always look three times when using them, if they use data that may come from the user, be sure that someone will definitely use it.
This piece is dangerous. If an attacker enters '../../../../../etc/passwd%00', he will be glad, but you are unlikely.
Do not forget that cookies are edited a little more complicated than what is visible in the address bar.
Therefore, everything that comes as a cookie is potentially an attack.
So you don’t need to store the user's access level or user ID in cookies.
It's best to let PHP handle this yourself using sessions.
By the way, in general, you need to store something in cookies very modestly and think three times, but is it necessary?
Always think of the data in the variables $ _GET, $ _POST, $ _COOKIE as an attack by an attacker.
Trust no one! :)
Content
Error display
Why so often I see going to some website something like this:
Warning: Use of undefined constant LOCAL_SERVER - assumed 'LOCAL_SERVER' in /web/includes/page-definitions.php on line 13
This is one of the standard PHP errors, which is a) ugly for the user; b) potentially dangerous.
Therefore, they must be intercepted and ordered.
Firstly, the error_reporting function allows us to decide which errors we want to see.
In principle, it’s enough to simply turn off the display of all errors (error_reporting (0)), but we don’t need this, because we want to know about errors.
The constant of all errors is E_ALL.
In the fifth version, the constant E_STRICT appeared, showing strict comments on the code.
Of course, it is desirable to see them, but they are not included in E_ALL, therefore we will use the numerical value error_reporting (8191), which absorbs everything, up to new errors of the sixth version.
Note for the curious: error_reporting (E_ALL | E_STRICT) is not suitable, because then PHP 4 will swear, not knowing what E_STRICT is. There will be no problems with the numerical value.
We add a check for DEBUG - a constant set in the config, and, using set_error_handler , we will catch errors in the already running service. By the way, your error reporter should return true, otherwise PHP will throw a standard error.
Result:
(As for comparing a variable with five parameters, I’m not sure about the choice of method: in_array is prettier and much slower, and the switch case case is faster, but completely ugly. Beauty is a subjective matter ...)
register_globals
Prior to version 4.2.0, the register_globals directive was enabled in PHP by default.
This led to the fact that many are used to the fact that if there is one in the form, then in the PHP code you can check if ($ username == 'admin') ...
However, this is a potential hole that led to many hacks.
Therefore, POST, GET, COOKIE variables must be accessed through superglobals $ _POST, $ _GET, $ _COOKIE.
To many, this seemed too difficult and the import_request_variables command , returning everything to normal, has become very popular .
So here.
Do not do this.
Another problem with register_globals:
150)
{
echo 'Boom!';
}
?>
If the user is not an administrator, and the variable $ user_level is not initialized
(it is not assigned a value of 0 at the beginning of the script, in the hope that it is 0 automatically),
then a bad person can add foo.php? User_level = 999 in the address bar and gain access.
SQL injection and magic_quotes
So popular among beginners is the design
dangerous. If the user enters the password 'OR` username` =' admin instead of the password, the system will let him in as an administrator.
The given example, of course, is elementary.
But if you do not solve the problem globally, you can always skip any query that is subject to SQL injection.
To combat this, the PHP developers decided to make sure that all the information coming from the user was processed and all the quotes were escaped (they are preceded by a slash, which the addslashes command does ).
What happened? All information from the user comes with slashes. Even the one like slashes should not receive. For example, comments on the article.
Not only that, this is not a 100 percent defense against SQL injection.
Decision.a) with all incoming information, remove slashes, if any. b) We filter all the information received in the SQL query specially for this purpose by the function mysql_real_escape_string (or an analogue for another database).
Remove slashes:
We create a function for filtering (mysql_real_escape_string is long, and tied to the verification format. And if you need to change the filter?)
And use it everywhere. As soon as some dynamic data is sent to SQL, we immediately use quote:
Data checking
Check everything that the user enters.
By default, he is an attacker.
Try not to filter , try to validate .
In other words, do not create a blacklist, create a white one.
Instead
use
So you will be sure that the information is clean and there will be no surprises.
If you are making a list of forbidden characters, you can always look at some bad% 00 and the like, which you probably don't know about.
Of course, there are situations when filtering is needed, for example, when a user writes a comment.
Then you have to cut off bad characters.
But in principle, you should try to validate.
There are several teams that must be handled very carefully.
These include, require, readfile, eval,,, system, exec, create_function, dir, fopen and the like.
Always look three times when using them, if they use data that may come from the user, be sure that someone will definitely use it.
This piece is dangerous. If an attacker enters '../../../../../etc/passwd%00', he will be glad, but you are unlikely.
Authentication
Do not forget that cookies are edited a little more complicated than what is visible in the address bar.
Therefore, everything that comes as a cookie is potentially an attack.
So you don’t need to store the user's access level or user ID in cookies.
It's best to let PHP handle this yourself using sessions.
By the way, in general, you need to store something in cookies very modestly and think three times, but is it necessary?
Conclusion
Always think of the data in the variables $ _GET, $ _POST, $ _COOKIE as an attack by an attacker.
Trust no one! :)