Rule 1: Never trust external data or input
The first thing that must be realized about Web Application Security is that external data should not be trusted. External data includes any data that is not directly input by programmers in PHP code. Before taking measures to ensure security, any data from any other source (such as GET variables, form POST, database, configuration file, session variables, or cookies) is untrusted.
For example, the following data elements can be considered safe because they are set in PHP.
Listing 1. Safe and flawless code
Reference content is as follows:
<? Php
$ MyUsername = tmyer;
$ ArrayUsers = array (tmyer, tom, tommy );
Define ("GREETING", hello there. $ myUsername );
?>
However, the following data elements are flawed.
List 2. insecure and defective code
Reference content is 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 defective? Because it is directly from form POST. You can enter any strings in this input field, including malicious commands used to clear files or run previously uploaded files. You might ask, "isn't it possible to avoid this risk using a client that only accepts letters of A-Z (Javascr into pt) Form validation script ?" Yes, this is always a good step, but as you will see later, anyone can download any form to their machine and modify it, then resubmit any content they need.
The solution is simple: you must run the cleanup code on $ _ POST [username. Otherwise, $ myUsername may be contaminated at any other time (such as in an array or constant.
A Simple Method for clearing user input is to use a regular expression to process it. In this example, only letters are allowed. It may be a good idea to limit a string to a specific number of characters, or to require that all letters be in lowercase.
Listing 3. Making user input secure
Reference content is 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
You already know that you cannot trust user input. You should also know that you should not trust the PHP configuration method on the machine. For example, make sure to disable register_globals. If register_globals is enabled, you may do some careless things, such as replacing the GET or POST string with the same name with $ variable. By disabling this setting, PHP forces you to reference the correct variables in the correct namespace. To use a variable from form POST, you should reference $ _ POST [variable]. In this way, the specific variable will not be misunderstood as a cookie, session, or GET variable.
Rule 3: if you cannot understand it, you cannot protect it.
Some developers use strange syntaxes, or organize statements very compact to form short but ambiguous code. This method may be highly efficient, but if you do not understand what the code is doing, you cannot decide how to protect it.
For example, which of the following two sections of code do you like?
Listing 4. Easy Code Protection
Reference content is 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 segment, it is easy to see that $ input is defective and needs to be cleaned up before it can be processed safely.
Rule 4: "defense in depth" is a new magic weapon
This tutorial uses examples to illustrate how to protect online forms and take necessary measures in PHP code that processes forms. Similarly, even if PHP regex is used to ensure that the GET variable is completely numeric, you can still take measures to ensure that the SQL query uses escape user input.
Defense in depth is not just a good idea. It ensures that you are not in serious trouble.
Now that we have discussed the basic rules, we will study the first threat: SQL injection attacks.
Prevent SQL injection attacks
In SQL injection attacks, you can manipulate the form or GET query string to add information to the database query. For example, assume there is a simple login database. Each record in this database has a username field and a password field. Create a logon form to allow users to log on.
Listing 5. Simple logon form
Reference content is as follows:
<Html>
<Head>
<Title> Login </title>
</Head>
<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>
</Html>
This form accepts the user name and password entered by the user, and submits the user input to the file verify. php. In this file, PHP processes data from the login form, as shown below:
Listing 6. Insecure PHP form processing code
Reference content is 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 ){
// Theyre okay to enter the application!
$ Okay = 1;
}
}
If ($ okay ){
$ _ SESSION [loginokay] = true;
Header ("index. php ");
} Else {
Header ("login. php ");
}
?>
This code looks okay, right? Hundreds or even thousands of PHP/MySQL sites around the world are using this code. Where is the error? Well, remember "user input cannot be trusted ". No information from the user is escaped, so the application is vulnerable to attacks. Specifically, any type of SQL injection attacks may occur.
For example, if you enter foo as the user name and or 1 = 1 as the password, the following string is actually passed to PHP and then the query is passed to MySQL:
Reference content is as follows:
<? Php
$ SQL = "select count (*) as ctr from users where username = foo and password = or 1 = 1 limit 1 ";
?>
This query always returns a Count value of 1, so PHP will allow access. By injecting some malicious SQL statements at the end of the password string, hackers can dress up as legitimate users.
To solve this problem, use the built-in mysql_real_escape_string () function of PHP as the package for any user input. This function is used to escape characters in a string, making it impossible for the string to pass special characters such as an apostrophes and allow MySQL to perform operations based on special characters. Listing 7 shows the Code with escape processing.
Listing 7. Safe PHP form processing code
Reference content is 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 ){
// Theyre okay to enter the application!
$ Okay = 1;
}
}
If ($ okay ){
$ _ SESSION [loginokay] = true;
Header ("index. php ");
} Else {
Header ("login. php ");
}
?>
Using mysql_real_escape_string () as the package for user input can avoid any malicious SQL Injection in user input. If you try to pass a malformed password through SQL injection, the following query will be passed to the database:
Reference content is as follows:
Select count (*) as ctr from users where username = foo and password = or 1 = 1 limit 1"
Unknown
There is nothing in the database that matches this password. Simply taking a simple step blocks a major vulnerability in a Web application. The experience here is that user input for SQL queries should always be escaped.
However, several security vulnerabilities need to be blocked. The next item is to manipulate the GET variable.
Prevents users from manipulating GET Variables
In the previous section, users are prevented from logging on with malformed passwords. If you are smart, you should apply the method you have learned to ensure that all user input in the SQL statement is escaped.
However, the user has logged on safely. A user with a valid password does not mean that he will follow the rules-he has