Disclaimer: This article is not the author’s original, originally reprinted from: github.com/SecurityPap…

1. The configuration

Php.ini basic security configuration


1.1 Cgi.force_Redirect Should be Enabled

Cgi.force_redirect is modified in php.ini, which is turned on by default. It prevents unauthenticated access when PHP is running cgi scripts. On IIS, OmniHTTPD, and Xitami it is disabled, but in all other cases it should be turned on.

; php.ini
cgi.force_redirect=1 ; 
Copy the code

1.2 Disabling ENABLE_DL

This directive only works with the Apache module version of PHP. You can turn dl() dynamically loading PHP modules on or off for each virtual machine or directory. The main reason to turn off dynamic loading is for security. With dynamic loading, it is possible to ignore all open_basEDIr restrictions. Dynamic loading is allowed by default, except in safe mode. In safe mode, dl() is always unavailable.

; php.ini
enable_dl=0 ; 
Copy the code

1.3 File_Uploads Should be Disabled

File_uploads is turned on by default, allowing you to upload files to your site. Because files from strangers are inherently untrustworthy and even dangerous, you should disable this feature unless your site absolutely needs it. If enabled, limit upload_max_filesize, upload_tmp_DIR, and post_max_size.

; php.ini
file_uploads = 0 ; 
Copy the code

1.4 Limiting File access permission by using open_basedir

Open_basedir, which opens all files by default, limits the number of files THAT PHP can open to the specified directory tree, including the files themselves. This instruction is not affected by safe mode on or off. When a script tries to open a file with methods such as fopen(),include, or gzopen(), the location of the file will be checked. PHP will refuse to open a file if it is outside the specified directory tree. All symbolic joins are parsed, so it is not possible to circumvent this limitation by symbolic joins.

Open_basedir should be configured with a directory that can then be accessed recursively. However, you should avoid using. (current directory) as the open_basedir value because it dynamically resolves special values during script execution. Specifying the working directory of the script will be used as the base directory, but this is dangerous because the working directory of the script can easily be changed by chdir().

In the httpd.conf file, open_basedir can be turned off like any other configuration option with “php_admin_value open_basedir None” (for example, in some virtual hosts). In Windows, directories are separated by semicolons. Separate directories with colons on any other system. As an Apache module, the open_basedir path in the parent directory is automatically inherited.

The restrictions specified with open_basedir are actually prefixes, not directory names. That is, “open_basedir = /dir/incl” will also allow access to “/dir/include” and “/dir/incls” if they exist. If you want to restrict access to only the specified directory, end the pathname with a slash. For example, open_basedir = /dir/incl/.

; php.ini
open_basedir="${USER}/scripts/data" ; 
Copy the code

1.5 Session. use_trans_SID Should be Disabled

The default is 0 (disabled). When cookies are disabled, PHP automatically appends the user’s session ID to the URL if it is enabled. Url-based session management has more security risks than cookie-based session management, and on the face of it, it seems like a good way to get users who disable cookies to use your site normally. In effect, it makes those users vulnerable to anyone hijacking their sessions. For example, a user may email a URL with a valid session ID to a friend, or the user may always have a URL with a session ID in the favorites to access the site with the same session ID. You can also retrieve the URL from browser history and server logs for the session ID.

; php.ini
session.use_trans_sid = 0 ; 
Copy the code

1.6 Session Management Cookies cannot be persistent

Cookies with no fixed life cycle or expiration date are called non-persistent or “session” cookies, meaning they only last as long as a browser session and disappear when the browser closes. Cookies with expiration dates are called “persistent” cookies, and they will be stored/retained until these expiration dates.

Apply non-persistent cookies to login sessions on managed web sites. To make the cookie nonpersistent, simply omit the Expires property. You can also use session.cookie_lifetime.


1.7 “allow_url_fopen” and “allow_url_include” should be disabled

Allow_url_fopen and allow_url_include are turned on by default and allow code to read scripts from urls. The ability to suck in executable code from outside the site, coupled with imperfect input cleanup, can expose the site to attackers. Even if the site’s input filtering is perfect today, there is no guarantee it will be in the future.

; php.ini
allow_url_fopen = 0
allow_url_include = 0
Copy the code

2. The coding

PHP secure coding recommendations


2.1 Use sleep() function with caution

Sleep () is sometimes used to prevent denial of service (DoS) attacks by limiting response rates. But because it takes up a thread, each request takes longer to service, making the application more vulnerable to DoS attacks rather than reducing the risk.

if (is_bad_ip($requester)) { sleep(5); // non-compliant usage}Copy the code

2.2 Prohibit dynamic code injection and execution

The eval() function is a way to run arbitrary code at runtime. The function eval() language construct is very dangerous because it allows arbitrary PHP code to be executed. Its use is therefore discouraged. If you have carefully verified that there is no alternative but to use this structure, be careful not to allow any user-supplied data to be passed in that has not been fully validated.

Eval ($code_to_be_dynamically_executed) // Non-compliant usageCopy the code

2.3 Hard coding of credentials is prohibited

Because it is easy to extract strings from a compiled application, credentials should never be hard-coded. This is especially true for distributed applications. Credentials should be stored outside of code in a strongly protected encryption profile or database.

$uname = getEncryptedUser(); $password = getEncryptedPass(); connect($uname, $password);Copy the code
$uname = "Steve "; $password = "blue"; connect($uname, $password);Copy the code

 

 

1. The configuration

Php.ini basic security configuration


1.1 Cgi.force_Redirect Should be Enabled

Cgi.force_redirect is modified in php.ini, which is turned on by default. It prevents unauthenticated access when PHP is running cgi scripts. On IIS, OmniHTTPD, and Xitami it is disabled, but in all other cases it should be turned on.

; php.ini
cgi.force_redirect=1 ; 
Copy the code

1.2 Disabling ENABLE_DL

This directive only works with the Apache module version of PHP. You can turn dl() dynamically loading PHP modules on or off for each virtual machine or directory. The main reason to turn off dynamic loading is for security. With dynamic loading, it is possible to ignore all open_basEDIr restrictions. Dynamic loading is allowed by default, except in safe mode. In safe mode, dl() is always unavailable.

; php.ini
enable_dl=0 ; 
Copy the code

1.3 File_Uploads Should be Disabled

File_uploads is turned on by default, allowing you to upload files to your site. Because files from strangers are inherently untrustworthy and even dangerous, you should disable this feature unless your site absolutely needs it. If enabled, limit upload_max_filesize, upload_tmp_DIR, and post_max_size.

; php.ini
file_uploads = 0 ; 
Copy the code

1.4 Limiting File access permission by using open_basedir

Open_basedir, which opens all files by default, limits the number of files THAT PHP can open to the specified directory tree, including the files themselves. This instruction is not affected by safe mode on or off. When a script tries to open a file with methods such as fopen(),include, or gzopen(), the location of the file will be checked. PHP will refuse to open a file if it is outside the specified directory tree. All symbolic joins are parsed, so it is not possible to circumvent this limitation by symbolic joins.

Open_basedir should be configured with a directory that can then be accessed recursively. However, you should avoid using. (current directory) as the open_basedir value because it dynamically resolves special values during script execution. Specifying the working directory of the script will be used as the base directory, but this is dangerous because the working directory of the script can easily be changed by chdir().

In the httpd.conf file, open_basedir can be turned off like any other configuration option with “php_admin_value open_basedir None” (for example, in some virtual hosts). In Windows, directories are separated by semicolons. Separate directories with colons on any other system. As an Apache module, the open_basedir path in the parent directory is automatically inherited.

The restrictions specified with open_basedir are actually prefixes, not directory names. That is, “open_basedir = /dir/incl” will also allow access to “/dir/include” and “/dir/incls” if they exist. If you want to restrict access to only the specified directory, end the pathname with a slash. For example, open_basedir = /dir/incl/.

; php.ini
open_basedir="${USER}/scripts/data" ; 
Copy the code

1.5 Session. use_trans_SID Should be Disabled

The default is 0 (disabled). When cookies are disabled, PHP automatically appends the user’s session ID to the URL if it is enabled. Url-based session management has more security risks than cookie-based session management, and on the face of it, it seems like a good way to get users who disable cookies to use your site normally. In effect, it makes those users vulnerable to anyone hijacking their sessions. For example, a user may email a URL with a valid session ID to a friend, or the user may always have a URL with a session ID in the favorites to access the site with the same session ID. You can also retrieve the URL from browser history and server logs for the session ID.

; php.ini
session.use_trans_sid = 0 ; 
Copy the code

1.6 Session Management Cookies cannot be persistent

Cookies with no fixed life cycle or expiration date are called non-persistent or “session” cookies, meaning they only last as long as a browser session and disappear when the browser closes. Cookies with expiration dates are called “persistent” cookies, and they will be stored/retained until these expiration dates.

Apply non-persistent cookies to login sessions on managed web sites. To make the cookie nonpersistent, simply omit the Expires property. You can also use session.cookie_lifetime.


1.7 “allow_url_fopen” and “allow_url_include” should be disabled

Allow_url_fopen and allow_url_include are turned on by default and allow code to read scripts from urls. The ability to suck in executable code from outside the site, coupled with imperfect input cleanup, can expose the site to attackers. Even if the site’s input filtering is perfect today, there is no guarantee it will be in the future.

; php.ini
allow_url_fopen = 0
allow_url_include = 0
Copy the code

2. The coding

PHP secure coding recommendations


2.1 Use sleep() function with caution

Sleep () is sometimes used to prevent denial of service (DoS) attacks by limiting response rates. But because it takes up a thread, each request takes longer to service, making the application more vulnerable to DoS attacks rather than reducing the risk.

if (is_bad_ip($requester)) { sleep(5); // non-compliant usage}Copy the code

2.2 Prohibit dynamic code injection and execution

The eval() function is a way to run arbitrary code at runtime. The function eval() language construct is very dangerous because it allows arbitrary PHP code to be executed. Its use is therefore discouraged. If you have carefully verified that there is no alternative but to use this structure, be careful not to allow any user-supplied data to be passed in that has not been fully validated.

Eval ($code_to_be_dynamically_executed) // Non-compliant usageCopy the code

2.3 Hard coding of credentials is prohibited

Because it is easy to extract strings from a compiled application, credentials should never be hard-coded. This is especially true for distributed applications. Credentials should be stored outside of code in a strongly protected encryption profile or database.

$uname = getEncryptedUser(); $password = getEncryptedPass(); connect($uname, $password);Copy the code
$uname = "Steve "; $password = "blue"; connect($uname, $password);Copy the code