PHP development can not violate the Security Rules filter user input _php Tips

Source: Internet
Author: User
Tags ereg form post php and mysql php form sql injection sql injection attack strlen tainted
As the most basic precaution you need to pay attention to your external submissions, do the first security mechanism to handle the firewall.
Rule 1: Never trust external data or input
The first thing you must realize about Web application security is that you should not trust external data. External data (outside) includes any data that is not entered directly by the programmer in the PHP code. Any data from any other source, such as a Get variable, form POST, database, configuration file, session variable, or cookie, is not trusted until the action is taken to ensure security.
For example, the following data elements can be considered safe because they are set in PHP.
Copy Code code as follows:

<?php
$myUsername = ' Tmyer ';
$arrayUsers = Array (' Tmyer ', ' Tom ', ' Tommy ');
Define ("greeting", ' hello there '. $myUsername);
?>

However, the following data elements are flawed.
Listing 2. Unsafe, flawed code
Copy Code code as follows:

<?php
$myUsername = $_post[' username ']; tainted!
$arrayUsers = Array ($myUsername, ' Tom ', ' Tommy '); tainted!
Define ("greeting", ' hello there '. $myUsername); tainted!
?>

Why is the first variable $myUsername flawed? Because it comes directly from the form POST. Users can enter any string in this input field, including malicious commands for purging files or running previously uploaded files. You might ask, "Can't you avoid this danger by using a client (javascrīpt) Form validation script that accepts only the letter A-Z?" "Yes, it's always a good step, but as you'll see later, anyone can download any form to their machine, modify it, and resubmit whatever they need."
The solution is simple: You must run cleanup code on $_post[' username '. If you do not, you may contaminate these objects at any other time that you use the $myUsername (for example, in arrays or constants).
An easy way to clean up user input is to use a regular expression to handle it. In this example, you only want to accept letters. It may also be a good idea to limit the string to a specific number of characters, or to require all letters to be lowercase.
Listing 3. Making user input Secure
Copy Code code as follows:

<?php
$myUsername = cleanInput ($_post[' username ')); clean!
$arrayUsers = Array ($myUsername, ' Tom ', ' Tommy '); clean!
Define ("greeting", ' hello there '. $myUsername); clean!
function CleanInput ($input) {
$clean = Strtolower ($input);
$clean = Preg_replace ("/[^a-z]/", "", $clean);
$clean = substr ($clean, 0,12);
return $clean;
}
?>

Rule 2: Disable PHP settings that make security difficult to implement
You know you can't trust user input, and you should know that you shouldn't trust the way you configure PHP on your machine. For example, be sure to disable register_globals. If you enable Register_globals, you may do something careless, such as using $variable to replace a GET or POST string with the same name. By disabling this setting, PHP forces you to reference the correct variable in the correct namespace. To use a variable from the form POST, you should refer to $_post[' variable '. This will not misunderstand this particular variable as a cookie, session, or get variable.
Rule 3: If you can't understand it, you can't protect it.
Some developers use strange syntax, or organize statements in a compact, short but ambiguous code. This approach can be efficient, but if you don't understand what the code is doing, you can't decide how to protect it.
For example, which paragraph of the following two sections of code do you like?
Listing 4. Making code easy to protect
Copy Code code as follows:

<?php
obfuscated code
$input = (isset ($_post[' username ')] ($_post[' username '): ");
unobfuscated Code
$input = ";
if (isset ($_post[' username ')) {
$input = $_post[' username '];
}else{
$input = ";
}
?>

In the second clear code snippet, it is easy to see that $input is flawed and needs to be cleaned before it can be safely processed.
rule 4: "Defense in Depth" is a new weapon
This tutorial will use an example to illustrate how to protect online forms while taking the necessary steps in processing the form's PHP code. Also, even if you use a PHP regex to ensure that a get variable is entirely numeric, you can still take steps to ensure that the SQL query uses escaped user input.
Defense in depth is not just a good idea, it can make sure you don't get into serious trouble.
Now that the basic rules have been discussed, let's look at the first threat: SQL injection attacks.
Preventing SQL injection attacks
In a SQL injection attack, a user adds information to a database query by manipulating the form or get query string. For example, suppose you have a simple login database. Each record in this database has a username and a password field. Build a login form that allows users to log in.
Listing 5. Simple login Form
Copy Code code as follows:

<title>Login</title>
<body>
<form action= "verify.php" method= "POST" >
<p><label for= ' user ' >Username</label>
<input type= ' text ' name= ' user ' id= ' user '/>
</p>
<p><label for= ' PW ' >Password</label>
<input type= ' password ' name= ' pw ' id= ' PW '
</p>
<p><input type= ' submit ' value= ' login '/></p>
</form>
</body>

This form accepts the user name and password entered by the user and submits the user input to the file named verify.php. In this file, PHP processes data from the login form, as follows:
listing 6. Unsafe PHP Form handling code
Copy Code code as follows:

<?php
$okay = 0;
$username = $_post[' user '];
$PW = $_post[' pw '];
$sql = "SELECT count (*) as Ctr from users where Username= '". $username. "' and password= '. $PW. "' Limit 1″;
$result = mysql_query ($sql);
while ($data = Mysql_fetch_object ($result)) {
if ($data->ctr = = 1) {
They ' re okay to enter the application!
$okay = 1;
}
}
if ($okay) {
$_session[' Loginokay '] = true;
Header ("index.php");
}else{
Header ("login.php");
}
?>

This code looks fine, right? This code is used by hundreds (even thousands) of php/mysql sites around the world. Where is it wrong? Well, remember "can't trust user input." There is no escaping any information from the user, so the application is vulnerable to attack. Specifically, any type of SQL injection attack may occur.
For example, if the user enters Foo as the user name and enters ' or ' 1′= ' 1 as the password, the following string is actually passed to PHP and the query is passed to MySQL:
Copy Code code as follows:

<?php
$sql = "SELECT count (*) as Ctr from users where Username= ' foo ' and password=" or ' 1′= ' 1′limit 1″;
?>

This query always returns the count value of 1, so PHP will allow access. By injecting some malicious SQL into the end of the password string, the hacker can dress up as a legitimate user.
The solution to this problem is to use PHP's built-in mysql_real_escape_string () function as a wrapper for any user input. This function escapes characters in the string, making it impossible for strings to pass special characters such as apostrophes and let MySQL operate on special characters. Listing 7 shows the code with escape processing.
listing 7. Secure PHP Form handling code
Copy Code code as follows:

<?php
$okay = 0;
$username = $_post[' user '];
$PW = $_post[' pw '];
$sql = "SELECT count (*) as Ctr from users where Username= '". Mysql_real_escape_string ($username). "' and password= '. Mysql_real_escape_string ($PW). "' Limit 1″;
$result = mysql_query ($sql);
while ($data = Mysql_fetch_object ($result)) {
if ($data->ctr = = 1) {
They ' re okay to enter the application!
$okay = 1;
}
}
if ($okay) {
$_session[' Loginokay '] = true;
Header ("index.php");
}else{
Header ("login.php");
}
?>

By using mysql_real_escape_string () as a wrapper for user input, you can avoid any malicious SQL injection in user input. If a user attempts to pass a malformed password through SQL injection, the following query is passed to the database:
Select COUNT (*) as Ctr from users where Username= ' foo ' and password= ' ' or \ ' 1\ ' =\ ' 1′limit
There is nothing in the database that matches this password. Using just one simple step, a big flaw in the Web application is blocked. The lesson here is that you should always escape user input for SQL queries.
However, there are several security vulnerabilities that need to be blocked. The next item is manipulating a get variable.
Prevent user from manipulating get variables
In the previous section, you prevented users from using malformed passwords to log on. If you are smart, you should apply the method you have learned to ensure that all user input to the SQL statement is escaped.
However, the user is now securely logged in. A user with a valid password does not mean he will follow the rules-he has many opportunities to do damage. For example, an application might allow users to view special content. All links point to locations such as template.php?pid=33 or template.php?pid=321. The section following the question mark in the URL is called a query string. Because the query string is placed directly in the URL, it is also called a Get query string.
In PHP, if register_globals is disabled, you can access the string using $_get[' pid '. In the template.php page, you might perform an operation similar to listing 8.
Listing 8. Example template.php
Copy Code code as follows:

<?php
$pid = $_get[' pid '];
We create an object of a fictional class Page
$obj = new Page;
$content = $obj->fetchpage ($pid);
And now we have a bunch of PHP this displays the page
?>

Is there anything wrong here? First, it is implicitly believed that the get variable pid from the browser is safe. What's going to happen? Most users are less intelligent and cannot construct semantic attacks. However, if they notice the pid=33 in the browser's URL location field, they may start messing around. If they enter another number, it may be fine, but what happens if you enter something else, such as a SQL command or a file name (such as/etc/passwd), or some other prank, such as a value of 3,000 characters long?
In this case, remember the basic rules and do not trust user input. Application developers know that the personal identifiers (PID) that template.php accepts should be numbers, so you can use the Is_numeric () function of PHP to ensure that you do not accept Non-numeric PID, as follows:
listing 9. Use Is_numeric () to restrict get variables
Copy Code code as follows:

<?php
$pid = $_get[' pid '];
if (Is_numeric ($pid)) {
We create an object of a fictional class Page
$obj = new Page;
$content = $obj->fetchpage ($pid);
And now we have a bunch of PHP this displays the page
}else{
Didn ' t pass the is_numeric () test, do something else!
}
?>

This method seems to be valid, but the following inputs can be easily checked by Is_numeric ():
100 (valid)
100.1 (there should be no decimal places)
+0123.45e6 (Scientific counting method--not good)
0xff33669f (hex--Dangerous!) Dangerous! )
So what should a security-conscious PHP developer do? Years of experience have shown that the best practice is to use regular expressions to make sure that the entire get variable consists of numbers, as follows:
listing 10. Using regular expressions to restrict get variables
Copy Code code as follows:

<?php
$pid = $_get[' pid '];
if (strlen ($pid)) {
if (!ereg ("^[0-9]+$", $pid)) {
Do something appropriate, like maybe logging them out or sending them back to home page
}
}else{
Empty $pid, so send them back to the home page
}
We create an object of a fictional class Page, which are now
Moderately protected from evil user input
$obj = new Page;
$content = $obj->fetchpage ($pid);
And now we have a bunch of PHP this displays the page
?>

All you need to do is use strlen () to check whether the variable is 0 or not, and if so, use a full digit regular expression to ensure that the data element is valid. If the PID contains letters, slashes, dots, or anything similar to hexadecimal, this routine captures it and masks the page from the user activity. If you look behind the Page class, you'll see that security-aware PHP developers have escaped the user input $pid, protecting the Fetchpage () method, as follows:
listing 11. To escape the Fetchpage () method
Copy Code code as follows:

<?php
Class page{
function Fetchpage ($pid) {
$sql = "Select Pid,title,desc,kw,content,status from page where pid= '". Mysql_real_escape_string ($pid). "'";
}
}
?>

You might ask, "Now that you've made sure that the PID is a number, why escape?" "Because you do not know how many different contexts and circumstances will use the Fetchpage () method. Must be protected in all places where this method is invoked, and the escape in the method embodies the meaning of defense-in-depth.
What happens if a user tries to enter a very long value, such as 1000 characters long, trying to initiate a buffer overflow attack? The next section discusses this in more detail, but you can now add another check to make sure the input PID has the correct length. You know that the maximum length of a database's PID field is 5 bits, so you can add the following check.
listing 12. Use regular expressions and length checks to limit get variables
Copy Code code as follows:

<?php
$pid = $_get[' pid '];
if (strlen ($pid)) {
if (!ereg ("^[0-9]+$", $pid) && strlen ($pid) > 5) {
Do something appropriate, like maybe logging them out or sending them back to home page
}
} else {
Empty $pid, so send them back to the home page
}
We create an object of a fictional class Page, which are now
Even more protected from evil user input
$obj = new Page;
$content = $obj->fetchpage ($pid);
And now we have a bunch of PHP this displays the page
?>

Now, no one can cram a 5,000-bit value into a database application--at least not in the place where the get string is involved. Imagine a hacker gnashing your teeth when trying to break through your application. And because the error reports are turned off, it's harder for hackers to scout.
Buffer overflow attack
A buffer overflow attack attempts to overflow a memory allocation buffer in a PHP application (or, more precisely, in the Apache or underlying operating system). Keep in mind that you might be writing a WEB application in a high-level language such as PHP, but you'll end up calling C (in Apache case). As with most low-level languages, C has strict rules for memory allocation.
A buffer overflow attack sends a large amount of data to the buffer, causing some data to overflow into an adjacent memory buffer, thereby damaging the buffer or overriding the logic. This can result in denial of service, corrupted data, or execution of malicious code on a remote server.
The only way to prevent buffer overflow attacks is to check the length of all user input. For example, if you have a FORM element that requires the user's name to be entered, add a MaxLength property with a value of 40 on the field and check it using substr () at the back end. Listing 13 gives a brief example of the form and PHP code.
listing 13. Check the length of user input
Copy Code code as follows:

<?php
if ($_post[' submit '] = = "Go") {
$name = substr ($_post[' name '],0,40);
}
?>
<form action= "<?php echo $_server[' php_self '";? > "method=" Post >
<p><label for= "Name" >Name</label>
<input type= "text" name= "name" id= "name" size= "20″maxlength=" 40″/></p>
<p><input type= "Submit" name= "submit" value= "Go"/></p>
</form>

Why do you provide both the MaxLength attribute and the substr () check at the back end? Because defense in depth is always good. Browsers prevent users from entering long strings that PHP or MySQL cannot safely handle (imagine someone trying to enter a 1,000-character name), and the back-end PHP check ensures that no one manipulates the form data remotely or in a browser.
As you can see, this approach is similar to the length of the GET variable PID used in the previous section to check for the strlen (). In this example, ignore any input values that are longer than 5 bits in length, but you can also easily truncate the value to the appropriate length, as follows:
listing 14. Change the length of the input get variable
Copy Code code as follows:

<?php
$pid = $_get[' pid '];
if (strlen ($pid)) {
if (!ereg ("^[0-9]+$", $pid)) {
If non numeric $pid, send them back to home page
}
}else{
Empty $pid, so send them back to the home page
}
We have a numeric PID, but it may is too long, so let ' s check
if (strlen ($pid) >5) {
$pid = substr ($pid, 0,5);
}
We create an object of a fictional class Page, which are now
Even more protected from evil user input
$obj = new Page;
$content = $obj->fetchpage ($pid);
And now we have a bunch of PHP this displays the page
?>

Note that buffer overflow attacks are not limited to long numeric strings or alphabetic strings. You may also see long hexadecimal strings (which often look like \xa3 or \xff). Remember, any buffer overflow attack is intended to overwhelm a particular buffer and place malicious code or instructions in the next buffer, destroying data or executing malicious code. The simplest way to deal with a hexadecimal buffer overflow is to not allow the input to exceed a specific length.
If you are dealing with a form text area that allows you to enter a long entry in a database, you cannot easily limit the length of the data on the client. After the data arrives in PHP, you can use regular expressions to clear any string that looks like hexadecimal.
listing 15. Prevent hexadecimal strings
Copy Code code as follows:

<?php
if ($_post[' submit '] = = "Go") {
$name = substr ($_post[' name '],0,40);
Clean out any potential hexadecimal characters
$name = Cleanhex ($name);
Continue processing .....
}
function Cleanhex ($input) {
$clean = Preg_replace ("![ \][XX] ([a-fa-f0-9]{1,3})! "," ", $input);
return $clean;
}
?>
<form action= "<?php echo $_server[' php_self '";? > "method=" Post >
<p><label for= "Name" >Name</label>
<input type= "text" name= "name" id= "name" size= "20″maxlength=" 40″/></p>
<p><input type= "Submit" name= "submit" value= "Go"/></p>
</form>

You may find that this series of operations is a bit too strict. After all, the hexadecimal string has a legitimate purpose, such as outputting characters in a foreign language. How to deploy a hexadecimal regex is up to you. A better strategy is to delete a hexadecimal string only if there are too many hexadecimal strings in a row, or if the character of a string exceeds a specific number (such as 128 or 255).
Cross-site scripting attacks
In Cross-site scripting (XSS) attacks, there is often a malicious user entering information in a table consignments (or through other user input) that inserts a malicious client tag into a procedure or database. For example, suppose you have a simple guest register program on your site that allows visitors to leave their names, e-mail addresses, and short messages. A malicious user can take this opportunity to insert something other than a short message, such as a picture that is not appropriate for another user or a javascrīpt that redirects a user to another site, or steals cookie information.
Fortunately, PHP provides the Strip_tags () function, which clears any content enclosed in HTML tags. The Strip_tags () function also allows you to provide a list of allowed tokens, such as <b> or <i>.
Data manipulation in the browser
A class of browser plug-ins allows users to tamper with the header elements and form elements on the page. With Tamper Data (a Mozilla plugin), you can easily manipulate simple forms that contain many hidden text fields to send instructions to PHP and MySQL.
The user can start Tamper Data before clicking Submit on the form. When you submit a form, he sees a list of form data fields. The Tamper data allows the user to tamper with it, and the browser completes the form submission.
Let's go back to the example we established earlier. The string length has been checked, the HTML markup has been cleared, and the hexadecimal character has been removed. However, some hidden text fields have been added, as follows:
Listing 17. Hide variables
Copy Code code as follows:

<?php
if ($_post[' submit '] = = "Go") {
//strip_tags
$name = Strip_tags ($_post[' name '));
$name = substr ($name, 0,40);
//clean out any potential hexadecimal characters
$name = Cleanhex ($name);
//continue processing ....
}
Function Cleanhex ($input) {
$clean = preg_replace ("![ \][XX] ([a-fa-f0-9]{1,3})! "," ", $input);
return $clean;
}
?>
<form action= "<?php echo $_server[' php_self '];? > "method=" Post >
<p><label for= "name" >Name</label>
<input type= "text" name= "name "Id=" name size= "20″maxlength=" 40″/></p>
<input type= "hidden" name= "table" value= "Users"/>
& L T;input type= "hidden" name= "action" value= "create"/>
<input type= "hidden" name= "status" value= "Live\"/> Br><p><input type= "Submit" name= "submit" value= "Go"/></p>
</form>

Note that one of the hidden variables exposes the table name: Users. You will also see an action field with a value of create. As long as you have basic SQL experience, you can see that these commands may control a SQL engine in the middleware. People who want to do great damage simply change the table name or provide another option, such as delete.
What's left of the question now? Remote form submission.
Remote form submission
The benefit of the WEB is that you can share information and services. The downside is the sharing of information and services, because some people have no scruples about doing things.
Take the form as an example. Anyone can access a Web site and create a local copy of the form using the File > Save as on the browser. He can then modify the action argument to point to a fully qualified URL (not pointing to formhandler.php, but pointing to http://www.yoursite.com/ formhandler.php, because the form is on this site), make any changes he wants, click Submit, and the server will receive this form data as a legitimate traffic stream.
First you might consider checking $_server[' http_referer ' to determine if the request came from your own server, which could block most malicious users, but not the most sophisticated hackers. These people are smart enough to tamper with the referrer information in the head so that the remote copy of the form looks like it was submitted from your server.
A better way to handle remote form submissions is to generate a token based on a unique string or timestamp and place the token in session variables and forms. After submitting the form, check to see if the two tokens match. If it doesn't match, you know someone is trying to send data from a remote copy of the form.
To create a random token, you can use the MD5 (), uniqid (), and Rand () functions built into PHP, as follows:
listing 18. Defense of Remote form submission
Copy Code code as follows:

<?php
Session_Start ();
if ($_post[' submit '] = = "Go") {
Check token
if ($_post[' token '] = = $_session[' token ']) {
Strip_tags
$name = strip_tags ($_post[' name '));
$name = substr ($name, 0,40);
Clean out any potential hexadecimal characters
$name = Cleanhex ($name);
Continue processing .....
}else{
Stop all processing! Remote form Posting attempt!
}
}
$token = MD5 (Uniqid (rand (), true);
$_session[' token ']= $token;
function Cleanhex ($input) {
$clean = Preg_replace ("![ \][XX] ([a-fa-f0-9]{1,3})! "," ", $input);
return $clean;
}
?>
<form action= "<?php echo $_server[' php_self '";? > "method=" Post >
<p><label for= "Name" >Name</label>
<input type= "text" name= "name" id= "name" size= "20″maxlength=" 40″/></p>
<input type= "hidden" name= token "value=" <?php echo $token;? > "/>
<p><input type= "Submit" name= "submit" value= "Go"/></p>
</form>

This technique is effective because session data cannot be migrated between servers in PHP. Even if someone gets your PHP source code, transfers it to your server, and submits information to your server, your server receives only the empty or malformed session token and the form token that was originally provided. They do not match, and remote form submission fails.
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.