Introduction to PHP Security programming suggestions
To provide Internet services, you must always be aware of security when developing code. Most PHP scripts may not care about security issues. this is largely because a large number of inexperienced programmers are using this language. However, there is no reason for you to create inconsistent security policies due to uncertainty in your code. When you put anything on the server that involves money, someone may try to crack it. Creating a Forum program or any form of shopping cart increases the possibility of being attacked to infinity.
Background
To ensure the security of your web content, there are some general security rules:
Do not trust the form
The attack form is simple. By using a simple JavaScript technique, you can limit that your form can only enter numbers 1 to 5 in the scoring field. If someone disables their browser's JavaScript function or submits custom form data, your client verification fails.
Users interact with your scripts through form parameters, so they are the biggest security risk. What should you learn? In PHP scripts, you always need to verify the data passed to any PHP script. In this article, we show you how to analyze and prevent cross-site scripting (XSS) attacks, which may hijack user creden (or even more serious ). You will also see how to prevent MySQL injection attacks that may tarnish or destroy your data.
Do not trust users
Assume that every piece of data your website obtains is filled with harmful code. Clean up each part, even if you believe no one will try to attack your site.
Disable global variables
The biggest security vulnerability you may have is that you have enabled the register_globals configuration parameter. Fortunately, this configuration is disabled by default in PHP 4.2 and later versions. IfRegister_globalsIn your php. ini file, you can disable this function by changing the register_globals variable to Off:
register_globals = Off
New programmers find it easy to register global variables, but they don't realize how dangerous this setting is. A server with global variables enabled automatically assigns any form of parameters to the global variables. Let's look at an example to learn how it works and why it is dangerous.
Suppose you have a script called process. php that inserts form data into your database. The initial form is as follows:
When you run process. php, PHP that enables global variable registration will assign this parameter to the $ username variable. This is better$ _ POST ['username']Or$ _ GET ['username']You can access it to save the number of times you press the key. Unfortunately, this will also leave you with security issues, because PHP will set the value of this variable to any value sent to the script through the GET or POST parameters, if you do not explicitly initialize the variable and you do not want anyone to operate on it, there will be a big problem.
Check the following script. if the value of the $ authorized variable is true, it displays the verified data to the user. Under normal circumstances, the value of the $ authorized variable is set to true only when the user passes the authentication of the hypothetical authenticated_user () function correctly. However, if you enableRegister_globalsAnyone can send a GET parameter, for example, authorized = 1 to overwrite it:
The implication of this story is that you should obtain form data from predefined server variables. All data transmitted to your web page through the post form will be automatically saved to$ _ POSTAll GET data is stored in$ _ GETIn a large array. The file upload information is stored in$ _ FILES. In addition$ _ REQUEST.
To access the username field from a POST method form, you can use$ _ POST ['username']. If username is in the URL$ _ GET ['username']. If you are not sure where the value comes from, use$ _ REQUEST ['username'].
$ _ REQUEST is a combination of $ _ GET, $ _ POST, and $ _ COOKIE array. If you have two or more values with the same parameter name, pay attention to which PHP will use. The default sequence is cookie, POST, and GET.
Recommended security configuration options
There are several PHP configuration settings that will affect the security function. Below are some of the items that should be used for production servers:
- Register_globalsSet to off
- Safe_modeSet to off
- Error_reportingSet to off. If an error occurs, this will send a visible error report to the user's browser. For production servers, use error logs instead. The development server can enable error logs after the firewall. (Here, according to the original logic and common sense, it should be "the development server can enable the error report, that is, on, if it is behind the firewall .")
- Disable these functions: system (), exec (), passthru (), shell_exec (), proc_open (), and popen ().
- Open_basedirIs the/tmp (to save session information) directory and web root directory, so that the script cannot access files outside these selected regions.
- Expose_phpSet to off. This function adds a PHP signature containing the version number to the Apache header.
- Allow_url_fopenSet to off. If you can pay attention to the way in your code to access files-that is, you verify all input parameters, this is not strictly required.
- Allow_url_includeSet to off. For anyone, there is no wise reason to access files contained through HTTP.
Generally, you should not trust the code that you find you want to use these features. Be especially careful when using code similar to the system () function-it is almost certainly flawed.
After these settings are enabled, let's take a look at some specific attacks and methods that can help you protect your servers.
SQL injection attacks
Since the query statements passed by PHP to the MySQL database are written in powerful SQL programming languages, some people may attempt SQL injection attacks by using MySQL statements in web query parameters. By inserting harmful SQL code snippets into the parameters, attackers will try to enter (or destroy) your server.
Assume that you have a form parameter that will eventually be put into the variable $ product. you use an SQL statement similar to the following:
$sql = "select * from pinfo where product = '$product'";
If the parameters are obtained directly from the form, you should use the database-specific escape functions that come with PHP, such:
$sql = 'Select * from pinfo where product = '"' mysql_real_escape_string($product) . '"';
If this is not done, someone may put the following code segment in the form parameters:
39'; DROP pinfo; SELECT 'FOO
The result of $ SQL is:
select product from pinfo where product = '39'; DROP pinfo; SELECT 'FOO'
Because the semicolon is the statement separator of MySQL, the database runs the following three statements:
select * from pinfo where product = '39'DROP pinfoSELECT 'FOO'
Okay, you lost your table.
Note that PHP and MySQL do not run this special syntax becauseMysql_query ()A function can process only one statement for each request. However, a subquery still takes effect.
To prevent SQL injection attacks, do the following:
- Always verify all parameters. For example, if you need a number, make sure it is a number.
- Always use the mysql_real_escape_string () function to escape any quotation marks and double quotation marks in the data.
Note: to automatically escape any form data, you can enable Magic Quotes ).
Some MySQL damages can be avoided by limiting MySQL User permissions. Any MySQL account can be limited to only allow specific types of queries on the selected table. For example, you can create a MySQL User that can only select rows. However, this is not very useful for dynamic data. In addition, if you have sensitive user information, some people may be able to access some of the data, but you do not want this. For example, a user accessing account data may try to inject code to access another user's account number instead of the number specified for the current session.
Prevent basic XSS attacks
XSS indicates cross-site scripting. Unlike most attacks, this vulnerability occurs on the client. The most common form of XSS is to place JavaScript in the content submitted by the user to steal data in the user cookie. Because most websites use cookies and sessions to verify visitors, the stolen data can be used to simulate this user-if it is a common user account, it will be very troublesome, if it is an administrator account or even a complete fiasco. If you do not use cookies and session IDs on the site, your users will not be vulnerable to attacks, but you should still understand how such attacks work.
Unlike MySQL injection attacks, XSS attacks are hard to prevent. Yahoo, eBay, Apple, and Microsoft have all been affected by XSS. Although the attack does not contain PHP, you can use PHP to strip user data to prevent attacks. To prevent XSS attacks, you should restrict and filter the data that users submit to your site. For this reason, most online bulletin boards do not allow HTML tags to be used in submitted data, but are replaced by custom tag formats. for example[B]And[Linkto].
Let's look at a simple script to prevent such attacks. For better solutions, you can use SafeHTML, which will be discussed later in this article.
function transform_HTML($string, $length = null) {// Helps prevent XSS attacks // Remove dead space. $string = trim($string); // Prevent potential Unicode codec problems. $string = utf8_decode($string); // HTMLize HTML-specific characters. $string = htmlentities($string, ENT_NOQUOTES); $string = str_replace("#", "#", $string); $string = str_replace("%", "%", $string); $length = intval($length); if ($length > 0) { $string = substr($string, 0, $length); } return $string;}
This function converts HTML-specific characters into HTML literal characters. A browser displays non-tagged text in any HTML using this script. For example, consider the following HTML string:
Bold Text
In general, HTML is displayed as follows:Bold Text
HoweverTransform_HTML ()It is rendered like the original input. The reason is that the tag string in the processed string is converted to an HTML entity.Transform_HTML ()The plain text of the result string looks like the following:
Bold Text
The essence of this function is the htmlentities () function call, which converts <,>, and &<,>, And&. Although this can handle most common attacks, experienced XSS attackers have another trick: using hexadecimal or UTF-8 to encode malicious scripts, rather than using plain ASCII text, so as to bypass your filter. They can send code in the GET variable of the URL and tell the browser, "This is a hexadecimal code. can you help me run it ?" A hexadecimal example looks like this:
When the browser renders this information, the result is:
《SCRIPT》Dosomethingmalicious《SCRIPT》
To prevent this, transform_HTML () uses additional steps to convert the # and % symbols into their entities, avoiding hexadecimal attacks and converting UTF-8-encoded data.
Finally, you can add an optional $ length parameter to intercept the string with the specified maximum length to prevent some people from crashing by using a long overloaded string.
Use SafeHTML
The problem with the previous script is relatively simple. it does not allow user tags of any type. Unfortunately, there are hundreds of methods that allow JavaScript to skip user filters and strip all HTML from user input. there is no way to prevent this.
Currently, no script can be cracked, although some are indeed better than most. The whitelist and blacklist can be used to reinforce security. The whitelist is simpler and more effective.
A whitelist solution is PixelApes's SafeHTML anti-cross-site scripting parser.
SafeHTML can identify valid HTML and trace and strip any dangerous tags. It is parsed using another software package called HTMLSax.
Follow these steps to install and use SafeHTML:
To http://pixel-apes.com/safehtml? Page = safehtml download the latest version of SafeHTML.
Put the file in the class folder on your server. This folder includes all the things required by the SafeHTML and HTMLSax functions.
Compile desafehtml class file (safehtml. php) in the script ).
Create a new safehtml object named $ SafeHTML.
Use $ safehtml-> parse () to clear your data.
This is a complete example:
parse($data);// Display result.echo 'The sanitized data is
' . $safe_data;?>
If you want to clear any other data in the script, you do not need to create a new object. in your entire script, you only need to use the $ safehtml-> parse () method.
What are possible problems?
The biggest mistake you may make is to assume that this class can completely avoid XSS attacks. SafeHTML is a very complex script that can check almost everything, but nothing can be guaranteed. You still need to perform parameter verification on your site. For example, this class cannot check the length of a given variable to ensure that it can adapt to the database fields. It also does not check the buffer overflow problem.
XSS attackers are very creative. they use various methods to try to achieve their goals. Read RSnake's XSS tutorial http://ha.ckers.org/xss.html to see how many methods are there to try to make the code skip the filter. A good programmer in the SafeHTML project has been trying to block XSS attacks, but it cannot be guaranteed that some people will not think of some strange and novel methods to skip the filter.
Note: an example of the serious impact of XSS attacks is http://namb.la/popular/tech.html, which shows how to create a JavaScript XSS worm that overload the MySpace server in one step.
Use one-way hash to protect data
This script performs one-way conversion on the input data. In other words, it can generate a hash signature for someone's password, but cannot decode it to obtain the original password. Why do you want this? The application stores the password. An administrator does not need to know the user's password. In fact, it is a good idea that only the user knows his/her own password. The system (and only the system) should be able to identify a correct password, which is a Unix password security model over the years. One-way password security works as follows:
When a user or administrator creates or changes the password of an account, the system hashes the password and saves the result. The host system discards the plaintext password.
When you log on to the system in any way, hash the entered password again.
The host system discards the entered plaintext password.
The current new hash password is compared with the previously saved hash.
If the hash password matches, the system grants the access permission.
The host system does not need to know the original password to complete these steps. In fact, the original password does not matter. One side effect is that if someone invades the system and steals the password database, the intruder will obtain a lot of hash passwords, but cannot reverse convert them into the original passwords. Of course, given enough time, computing power, and weak user passwords, an attacker may still use dictionary attacks to find the passwords. Therefore, do not touch your password database easily. if someone does, let every user change their password.
Encryption Vs hash
Technically speaking, the hash process is not encrypted. Hash and encryption are different for two reasons:
Unlike encryption, hash data cannot be decrypted.
It is possible (but rare) that two different strings will generate the same hash. There is no guarantee that the hash is unique, so do not use the hash as the unique key in the database.
function hash_ish($string) { return md5($string);}
The above md5 () function returns a 32-character hexadecimal string based on the RSA Data Security company's message digest algorithm (MD5. Then you can insert the 32-bit string into the database and compare it with another md5 string, or directly use the 32 characters.
Cracking script
It is almost impossible to decrypt the MD5 data. Or hard. However, you still need a good password, because it is still very easy to generate a hash database using an entire dictionary. There are some online MD5 dictionaries when you enter06d80eb0c50b49a509b49f2424e8c805The result "dog" is displayed ". Therefore, even though MD5 cannot be decrypted technically, there is still a vulnerability here. if someone gets your password database, you can be sure that they will use the MD5 dictionary to decrypt it. Therefore, when creating a password-based system, pay special attention to the password length (minimum 6 characters, 8 may be better) and including letters and numbers. Make sure that the password is not in the dictionary.
Encrypt data with Mcrypt
If you do not need to view the password in readable form, it is enough to use MD5. Unfortunately, there are not always options here. if you provide encrypted storage of someone's credit card information, you may need to decrypt it somewhere later.
One of the earliest solutions was the Mcrypt module, a plug-in used to allow PHP high-speed encryption. The Mcrypt Library provides over 30 encryption computing methods and provides a password to ensure that only you (or your users) can decrypt data.
Let's take a look at the usage. The following script contains functions for data encryption and decryption using Mcrypt:
Mcrypt ()The function requires the following information:
- Data to be encrypted
- The password used to encrypt and unlock data, also known as a key.
- The calculation method used to encrypt data, that is, the algorithm used to encrypt data. This script usesMCRYPT_SERPENT_256But you can choose from many algorithms, includingMCRYPT_TWOFISH192,MCRYPT_RC2,MCRYPT_DES, AndMCRYPT_LOKI97.
- Data encryption mode. There are several modes you can use, including the Electronic Cipher book and the encrypted Feedback (Cipher Feedback ). Use this scriptMCRYPT_MODE_CBCPassword block link.
- OneInitialization vector-It is also called IV or seed, which is used to set the extra binary bit of the seed for the encryption algorithm. That is, additional information that makes the algorithm more difficult to crack.
- The length of the key and the IV string, which may vary with encryption and block. UseMcrypt_get_key_size ()AndMcrypt_get_block_size ()Function to obtain the appropriate length, and then useSubstr ()The function truncates the key value to a proper length. (If the key length is shorter than the required value, do not worry. Mcrypt will be filled with 0 .)
If someone steals your data and phrases, they can only try encryption algorithms one by one until they find the correct one. Therefore, before using it, we useMd5 ()Functions increase security. even if they get data and phrases, intruders cannot get what they want.
Intruders need functions, data, and passwords at the same time. if so, they may have full access to your server. you can only clean them.
There is also a small problem with the data storage format. Mcrypt returns encrypted data in a hard binary format, which may cause a terrible error when you store it in the MySQL field. Therefore, we useBase64encode ()AndBase64decode ()Function conversion to SQL-compatible letter formats and searchable rows.
Cracking script
In addition to experimenting with multiple encryption methods, you can also add some convenience in the script. For example, you do not need to provide keys and modes each time, but declare them as global constants in the contained files.
Generate random password
Random (but difficult to guess) strings are important to user security. For example, if someone loses the password and you use the MD5 hash, you are not allowed to retrieve it. Instead, a secure random password should be generated and sent to the user. To access services on your site, another application for generating random numbers will create a valid link. The following is a function used to create a password:
0) && (! is_null($num_chars))) { $password = ''; $accepted_chars = 'abcdefghijklmnopqrstuvwxyz1234567890'; // Seed the generator if necessary. srand(((int)((double)microtime()*1000003)) ); for ($i=0; $i<=$num_chars; $i++) { $random_number = rand(0, (strlen($accepted_chars) -1)); $password .= $accepted_chars[$random_number] ; } return $password; }}?>
Script
Make_password ()The function returns a string, so you need to provide the length of the string as the parameter:
The function follows these steps:
- Function assurance$ Num_charsIs a non-zero positive integer.
- Function initialization$ Accepted_charsThe variable is a list of characters that the password may contain. This script uses all lowercase letters and numbers 0 to 9, but you can use any character set you like. (LCTT Note: Sometimes you can remove 0, O, 1, and l to facilitate visual recognition .)
- The random number generator requires a seed to obtain a series of class random values (PHP 4.2 and later versions are not required and will be automatically seeding ).
- Function loop$ Num_charsTime, one character in the password is generated in each iteration.
- View the script for each new character$ Accepted_charsSelect a number between 0 and length, and then add$ Accepted_charsTo $ password.
- After the loop ends, the function returns$ Password.
License
This article, including relevant source Code and files, is published under The Code Project Open License (CPOL) protocol.
Via: http://www.codeproject.com/Articles/363897/PHP-Security
Author: SamarRizvi translator: ictlyh proofreader: wxy
This article was originally translated by LCTT and launched with the Linux honor in China
Source: https://linux.cn/article-5868-1.html