Securing Web Applications – Best Practices
Finding your web site hacked and defaced one fine moring would be a nightmare for any web application developer. For securing from the same there are some recommendations. Through out the past years, we have summarized our strategy on the expectation that this would help others to build applications that are difficult to penetrate. Mostly the content of the article would be refering to PHP scripting language, and most others should not be any different.
Common web application security holes could be broadly categorised as follows
- Non validated user input
- Non standard authentication methods
- Poor session management
- Cross Site Scripting ( implies non validated inupt )
- Improper Error Handling ( implies configuration disclosure )
- Insecure storage ( file system security )
- Careless Configuration Management ( web readable configuration files )
- Injection Flaws ( sql, shell and downloads )
Web applications will use input from requests (and some times files) to decide how to respond. Attackers can change any part of an HTTP request, including the url, query string, headers, cookies, form fields, and hidden fields, to try to bypass the site’s security mechanisms or to deface the site.
So developers should be aware of these and try to accept only validated input. Contrary to discarding invalid input, it is always recommended to accept only valid input. For any said vaiable, if we are expecting integer value, make sure that it contains only integer. Either by using the filter_var built in method or using sprintf or intval. The filter_var provides a much more flexible method for validating as well as santitizing. The corresponding documentation provides more insights towards some of the caveats. Importing variables from _REQUEST means you are trying to get variables from _GET or _POST without knowing which method it is. Avoid the variable method and always take from the expected method of submission only.
Creating authentication by registering a variable into the session would be the best choice for maintaing the authenticated session. But some do go for cookie based authentication with setting cookies like isAdmin=1. Which invites trouble. Keeping sessions into database could be an option to secure the sessions from being tampered with on shared hosts. Which helps us from session hijacking.
Standard default installation of php may be having error reporting enabled and display errors true set in the php.ini. Shared hosts with administrators of great and vast experience may not configure such a way. But still make sure that errors in the php will not show out on the browser. This can only be achieved using the .htaccess or directory wide php.ini.
File uploads cannot be avoided with a great many applications. And normal trend is to store them into the filesystem with web requestable url. Means store into a folder that is readable by the web server. To the extend possible uploaded files should be stored in a folder that is not web accessable. In other extreme cases the files store should be stamped with ‘php flag engine off’ put into a .htaccess. In all cases files uploaded should be validated using the magic header. In php use the Fileinfo Functions and make sure the file is of permitted type before accepting it. The identification can be performed by working on the file while it is in the temporary upload directory. Even better would be to upload files to a repository which is published through another web server or a sub domain which has the scripting engine permanently disabled. This is possible eaisly on the Amazon S3 ( which provides direct upload to S3 ).
Common trend to create configuration files with extensions .ini or .inc may already be protected but backup files ending with ~ or .bak extensions could provide a vulnerablity. Also changelog.txt, readme.txt and version information from open source applications should be removed from any production url.
Santizing of user input should save from sql injection vulnerabilities most of the time. Even then the final sql query should only be built with mysql_real_esacpe_string or mysqli_real_esacpe_string if at all you are not using prepared statements and PDO.
Above all these points should never be a disaster recovery plan rather should be a coding practice.