Transfer from http://www.codeceo.com/article/php-safe-programming.html, get more information please visit the original
Brief introduction
To provide Internet services, you must always maintain a sense of security when developing your Code. Probably most PHP scripts don't care about security, largely because there are a lot of inexperienced programmers using the Language. however, There is no reason for you to cause inconsistent security policies because of uncertainty about your Code. When you put anything on the server that involves money, there is a chance that someone will try to crack it. Create a forum program or any form of shopping cart, the likelihood of being attacked has risen to Infinity.
Background
To ensure your Web content is secure, here are some general security guidelines:
Don't trust the forms
Attacking the form is Simple. By using a simple JavaScript technique, you can limit your form to allow 1 to 5 numbers to be filled in the scoring field. If someone shuts down their browser's JavaScript functionality or submits custom form data, your Client's validation fails.
Users interact primarily with your scripts through form parameters, so they are the greatest security risk. What do you have to learn? In a PHP script, you always validate the data passed to any PHP script. In this article, we show you how to analyze and protect against Cross-site scripting (XSS) attacks, which can hijack user credentials (or even more). You will also see how to prevent a MySQL injection attack that will taint or destroy your Data.
Don't trust users
Assume that every piece of data your site gets is filled with harmful code. Clean up every part, even if you believe that no one will try to attack your Site.
Close Global Variables
The maximum security vulnerability you might have is to enable the Register_globals configuration Parameter. fortunately, PHP 4.2 and later versions disable this configuration by Default. If register_globalsis turned on, you can turn off the function by changing the register_globals variable to off in your php.ini file:
Off
Novice programmers find it convenient to register global variables, but they will not realize how dangerous this setting is. A server with global variables enabled automatically assigns parameters of any kind to global variables. To understand how it works and why it is dangerous, let's look at an example.
Suppose you have a script called process.php that inserts form data into your database. The initial form looks like this:
<name=type=size=maxlength="up" >
When you run process.php, PHP that is enabled to register the global variables assigns the parameter to the $username Variable. This will save keystrokes more than accessing it through $_post[' username ' or $_get[' username '] . unfortunately, This also leaves you with a security problem because PHP sets the value of the variable to any value that is sent to the script by a GET or POST parameter, and if you do not initialize the variable with a display and you do not want anyone to manipulate it, there is a big problem.
Look at the following script, if the value of the $authorized variable is true, it will show the user the validated Data. Under normal circumstances, the value of $authorized variable is set to True only if the user correctly passes the hypothetical Authenticated_user () function Validation. But if you enable register_globals, anyone can send a get parameter, such as authorized=1, to overwrite It:
<?php//Define $authorized = True if user is authenticatedif (authenticated_user ()) { true;} ?>
The moral of this story is that you should get form data from predefined server Variables. All data passed to your Web page via the Post form is automatically saved to a large array called $_post , and all GET data is stored in a large array of $_get . File upload information is stored in a special data called $_files . In addition, there is a compound variable called $_request .
To access the Username field from a single POST method form, you can use $_post[' username '. If username uses $_get[' username 'in the URL. If you are unsure where the value comes from, use $_request[' username '.
<?php$post_value = $_post[' post_value '); $get _value = $_get[' get_value ']; $some _variable = $_request[ ?>
$_request is a combination of $_get, $_post, and $_cookie arrays. If you have two or more values with the same parameter name, note which PHP will Use. The default order is the cookie, POST, and then GET.
Recommended Security Configuration options
Here are a few PHP configuration settings that can affect security features. Here are some of the things that should obviously be used for production servers:
- register_globals set to Off
- Safe_mode set to Off
- error_reporting is set to off. If an error occurs, this sends a visible error report message to the User's browser. For production servers, use the error log Instead. The development server can enable the error log if it is behind a firewall. (lctt: here according to the original logic and common sense, should be "development server if you can enable error reporting behind the firewall, that is, On.") ”)
- Deactivate these functions: system (), exec (), passthru (), shell_exec (), proc_open (), and Popen ().
- the open_basedir is the/tmp (to save session Information) directory and Web root so that the script cannot access files outside these selected Regions.
- expose_php is set to off. This feature adds a PHP signature containing the version number to the Apache header.
- Allow_url_fopen is set to off. If you are able to notice the way your code accesses files-that is, you validate all input parameters, This is not strictly required.
- Allow_url_include is set to off. For anyone, There is no sensible reason to want to access files that are contained through HTTP.
In general, If you find code that wants to use these features, you should not trust it. In particular, be careful about using code like the system () Function-it's almost certainly flawed.
With these settings enabled, Let's take a look at some specific attacks and how you can help protect your server.
SQL injection attacks
Since the query that PHP passed to the MySQL database was written in a powerful SQL programming language, some people were at risk of trying SQL injection attacks by using MySQL statements in Web query Parameters. By inserting an unwanted SQL snippet into a parameter, an attacker attempts to enter (or Destroy) your server.
If you have a form parameter that will eventually be put into a variable $product, you use an SQL statement similar to the following:
$sql = "' $product '";
If the parameters are obtained directly from the form, you should use PHP's own database-specific escape functions, similar to the following:
$sql = ' "' ";
If you don't, someone might put the following code snippet in the form Parameter:
' FOO
So the $sql result is:
' FOO '
Because the semicolon is the statement delimiter for MySQL, the database runs the following three statements:
' pinfo 'DROP 'FOO '
well, You've lost your Watch.
Note that PHP and MySQL do not actually run this particular syntax because the mysql_query () function allows only one statement per Request. however, one subquery still takes effect.
To prevent SQL injection attacks, do these two things:
- Always Validate all Parameters. For example, If you need a number, make sure it is a number.
- Always use the mysql_real_escape_string () function on data to escape any quotation marks and double quotes in the Data.
Note: to automatically escape any form data, you can turn on magic quotation marks (magicQuotes).
Some MySQL breaches can be avoided by restricting MySQL user permissions. Any MySQL account can be restricted to only allow certain types of queries on selected Tables. For example, you can create a MySQL user who can only select Rows. however, This is not very useful for dynamic data, and if you have sensitive user information, Some people may be able to access some of the data, but you don't want to. For example, a user accessing account data might try to inject code that accesses another Person's account number, rather than the number specified for the current Session.
Prevent basic XSS attacks
XSS represents a Cross-site script. Unlike most attacks, the vulnerability occurs on the Client. The most common basic form of XSS is to place JavaScript in user-submitted content to steal data from user Cookies. Since most sites use cookies and sessions to authenticate visitors, the stolen data can be used to impersonate the user-if a common user account is in trouble, if the administrator account is even a complete fiasco. If you do not use cookies and session IDs in your site, your users will not be vulnerable, but you should still understand how this attack works.
Unlike MySQL injection attacks, XSS attacks are difficult 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 peel off user data to prevent attacks. To prevent XSS attacks, you should restrict and filter the data that users submit to your Site. It is for this reason that most online bulletin boards do not allow the use of HTML tags in submitted data, but instead use custom label formats, such as [b] and [linkto].
Let's look at a simple script to prevent this type of ATTACK. For a more complete solution, you can use safehtml, which is 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 ( "#", "& #35;", $string); $string = str_ Replace (if ($length > 0) {$string = substr ($string, 0, $length); } return $string;}
This function converts html-specific characters to HTML literal characters. A browser renders non-tagged text in any HTML that passes through the script. For example, consider the following HTML string:
<strong>bold Text</strong>
In general, the HTML will appear as:Bold Text
however, after transform_html () , it is rendered as if it were the original Input. The reason is that the label string in the processed string is converted to an HTML Entity. The plain text of the result string for transform_html () looks like this:
<strong>bold Text</strong>
The essence of this function is the htmlentities () function call, which converts <, >, and & to <,>, and &. Although this deals with most common attacks, experienced XSS attackers have another trick: encode malicious scripts in hexadecimal or UTF-8 instead of plain ASCII text, hoping to bypass your Filters. They can send the code in the URL's GET variable, tell the browser, "this is the hexadecimal code, can you help me run it?" "a Hexadecimal example looks like this:
<a href="http://host/a.php?variable=%22%3e%3c%53%43%52%49%50%54%3e%44%6f%73%6f%6d%65%74%68%69%6e%67%6d% 61%6c%69%63%69%6f%75%73%3c%2f%53%43%52%49%50%54%3e ">
When the browser renders this information, the result is:
<href=<script>dosomethingmalicious</script>
To prevent this, transform_html () takes additional steps to convert the # and% symbols to their entities, thus avoiding hex attacks and converting UTF-8 encoded DATA.
finally, to prevent some people from overloading strings with a long input and causing something to crash, you can add an optional $length parameter to intercept the string you specify for the maximum Length.
Using safehtml
The problem with the previous script is simple and it does not allow any type of user Tag. unfortunately, There are hundreds of ways to make JavaScript skip the User's filter and to strip all HTML from user input, there is no way to prevent this.
currently, no script can be guaranteed to be cracked, although some are better than most. There are two ways to secure a whitelist and blacklist, and the whitelist is simpler and more Effective.
A white-list solution is Pixelapes's safehtml anti-cross-site scripting Parser.
SafeHTML can identify valid HTML and can track and peel off any hazard tags. It is parsed with another package called Htmlsax.
Follow the steps below to install and use Safehtml:
- Download the latest version of safehtml to Http://pixel-apes.com/safehtml/?page=safehtml.
- Put the files in your Server's class Folder. This folder includes everything you need for the safehtml and Htmlsax Features.
- Include the SafeHTML class file (safehtml.php) in the Script.
- Creates a new SafeHTML object that is named $safehtml.
- Use the $safehtml->parse () method to clean up your Data.
This is a complete example:
<?php/* If you ' re storing the htmlsax3.php in the/classes directory, along with the safehtml.php script, define Xml_htmlsax3 As a null string. */define (xml_htmlsax3,"); //Include the class File. require_once (' classes/safehtml.php '); Define some sample bad code. $data = "this data would raise an alert <script>alert (' XSS Attack ') </script> ;"; //Create a safehtml object. $safehtml = new safehtml (); Parse and sanitize the Data. $safe _data = $safehtml->parse ($data); //Display Result. Echo ' The sanitized data is <br/> '. $safe _data;? >
If you want to clean up any other data in the script, you don't need to create a new object; you only need to use the $safehtml->parse () method in your entire script.
What might be the problem?
The biggest mistake you can make is to assume that this class can completely avoid XSS attacks. SafeHTML is a fairly complex script that can almost check everything, but nothing is Guaranteed. You still need to do a parameter validation on your Site. For example, the class cannot check the length of a given variable to ensure that it adapts to the field of the Database. It also does not check for buffer overflow Issues.
XSS attackers are creative, and they use a variety of methods to try to reach their goals. You can read Rsnake's XSS tutorial http://ha.ckers.org/xss.html and see how many methods here try to get the code to skip the Filter. SafeHTML Project A good programmer has been trying to block XSS attacks, but there is no guarantee that some people will not think of strange and novel ways to skip Filters.
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 overloads the MySpace server Step-by-step.
Protect data with a one-way hash
The script transforms the input data one-way, in other words, it generates a hash signature on Someone's password, but does not decode it to get the original Password. Why do you want to do that? The application stores the Password. An administrator does not need to know the User's password, in fact, only the user knows his/her own password is a good Idea. The system (and only the System) should be able to identify a correct password, which is the Unix password security model for many Years. One-way password security works as Follows:
- When a user or administrator creates or changes an account password, the system hashes the password and saves the Result. The host system discards the plaintext Password.
- When the user logs on to the system in any way, the entered password is hashed again.
- The host system discards the plaintext password Entered.
- The password for the current new hash and the previously saved OTP Comparison.
- If the hashed password matches, the system grants ACCESS.
The host system does not need to know the original password to do this; in fact, the original password completely indifferent. One side effect is that if someone invades the system and steals the password database, the intruder obtains a lot of hashed passwords, but cannot reverse them back into the original Password. of course, given enough time, computing power, and weak user passwords, it is possible for an attacker to use a dictionary attack to find a Password. So don't let people touch your password database easily, and if someone does, let each user change their password.
Crypto Vs Hash
technically, The hashing process is not encrypted. Hashing and encryption are different, there are two reasons:
Unlike encryption, hash data cannot be decrypted.
It is possible (but very rare) that two different strings will produce the same Hash. There is no guarantee that the hash is unique, so do not use a hash like a unique key in the Database.
Hash_ish($string) { return MD5 ($string);}
The MD5 () function above returns a 32-character hexadecimal string based on the RSA data security Company's message digest algorithm (that is, MD5). You can then insert that 32-bit string into the database and compare it to another MD5 string, or use these 32 characters directly.
Hack script
It is almost impossible to decrypt MD5 Data. or, It's Hard. however, you still need a good password because it is still simple to generate a hash database with an entire dictionary. There are some online MD5 dictionaries that will get the result "dog" when you enter 06d80eb0c50b49a509b49f2424e8c805 . so, while technically MD5 can't be decrypted, There's still a loophole here, and if someone gets your password database, you can be sure they'll use the MD5 dictionary to decipher it. therefore, when you create a password-based system, pay particular attention to the length of the password (minimum 6 characters, 8 may be better) and include letters and Numbers. And make sure that the password is not in the Dictionary.
Encrypt data with Mcrypt
If you don't need to see the password in readable form, it's enough to use MD5. unfortunately, There is not always an option, and if you provide an encrypted way to store Someone's credit card information, You may need to decrypt it somewhere in the Back.
One of the first solutions was the Mcrypt module, a plug-in that allows PHP to encrypt at high Speed. The Mcrypt Library provides more than 30 computing methods for encryption, and provides a password to ensure that only you (or your users) can decrypt the Data.
Let's take a look at how to use it. The following script contains functions for encrypting and decrypting data using Mcrypt:
<?php$data ="Stuff you want encrypted"; $key ="Secret passphrase used to encrypt your data"; $cipher ="mcrypt_serpent_256"; $mode ="mcrypt_mode_cbc";functionencrypt ($data, $key, $cipher, $mode) { //Encrypt datareturn (string) base64_encode (mcrypt_encrypt ( $cipher, substr (md5 ($key), 0,mcrypt_get_key_size ($cipher, $mode)), $data, $mode, substr ( MD5 ($key), 0,mcrypt_get_block_size ($cipher, $mode)));} function decrypt ($data, $key, $cipher, $mode) {//Decrypt data return (string) mcrypt_decrypt ($cipher, substr (md5 ($key), 0,mcrypt_get_key_size ($cipher, $mode)), base64_decode ($data), $mode, substr (md5 ($key), 0,mcrypt_get_block_size ($cipher, $mode)));} ?>
the mcrypt () function requires several information:
- Data that needs to be encrypted
- A password used to encrypt and unlock data, also known as a key.
- The computational method used to encrypt data, which is the algorithm used to encrypt the Data. The script uses mcrypt_serpent_256, but you can choose from a number of algorithms, including mcrypt_twofish192,mcrypt_rc2,mcrypt_des , and mcrypt_loki97.
- The mode of encrypting Data. Here are a few patterns you can use, including the electronic cipher (Electronic Codebook) and the cryptographic feedback (Cipher Feedback). The script uses the MCRYPT_MODE_CBC cipher block Link.
- An initialization vector -also known as IV or Seed-is used to set the additional bits of the seed for the cryptographic algorithm. Additional information that makes the algorithm more difficult to Crack.
- The length of the key and IV string, which may vary depending on the encryption and the BLOCK. Use the mcrypt_get_key_size () and mcrypt_get_block_size ( ) functions to obtain the appropriate length, and then use the substr () function to intercept the value of the key to the appropriate Length. (if the length of the key is shorter than required, don't worry, Mcrypt will fill it with 0.) )
If someone steals your data and phrases, they can only try to encrypt the algorithm until they find the right one. so, before we use it, we add security by using the MD5 () function on the keys, and even if they get the data and phrases, the intruder can't get what they want.
Intruders need functions, data and passwords at the same time, and if that's the case, they might get full access to your server, and you can only clean it up.
There is also a small problem with the data storage format. Mcrypt returns encrypted data in a Hard-to-understand binary form, which makes it possible to have scary errors when you store them in a MySQL field. therefore, we use the base64encode () and base64decode () functions to convert to a SQL-compatible letter format and to retrieve Rows.
Hack script
In addition to experimenting with multiple encryption methods, You can also add some convenience to your script. For example, instead of supplying keys and patterns each time, you declare them as global constants in the contained Files.
Generate Random passwords
A random (but hard to Guess) string is important in user Security. For example, If someone loses the password and you use the MD5 hash, you cannot, and you do not want to find it back. instead, a secure random password should be generated and sent to the User. In order to access the services of your site, another application that generates random numbers creates a valid Link. Here is a function to create a password:
<?phpfunction make_password ($num _chars) {if ((is_numeric ($num _chars)) && ($num _chars > 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 ( Span class= "hljs-number" >0, (strlen ($accepted _chars) -1); $password. = $accepted _chars[$random _number]; } return $password;}} ?>
Using scripts
the Make_password () function returns a string, so all you need to do is provide the length of the string as an argument:
<?php$fifteen_character_password = Make_password ();? >
The function works as Follows:
- The function ensures that the $num _chars a Non-zero positive integer.
- The function initializes $accepted the _chars variable is a list of characters that the password may contain. The script uses all lowercase letters and numbers 0 through 9, but you can use any character set you like. Lctt: Sometimes you can get rid of 0 and o,1 and L in order to make it easy for the naked eye to Recognize. )
- The random number generator requires a seed to obtain a series of random values (not required in PHP 4.2 and later, and will be seeded automatically).
- The function loops $num _chars times, generating one character in the password for each Iteration.
- For each new character, the script looks at the length of the $accepted _chars , selects a number between 0 and length, and then adds $accepted the character in _chars to the index value to the $password.
- After the loop ends, the function returns $password.
License
This article, including the relevant source code and files, is released under the code Project Open License (cpol) agreement.
PHP Security Programming Recommendations (rpm)