Showing posts with label Programming. Show all posts
Showing posts with label Programming. Show all posts

PHP Security and Sessions

Learn how to secure your PHP pages swiftly using a simple include file that should be included at the top of every page. Read more ...This article demonstrates an easy way to maintain sessions and security (or authorization) in PHP. It does NOT use the PHP built in session support.

The following method will allow you to easily secure any PHP page by simply including a file at the top of every page. In this tutorial you will:

a) Create your database structure
b) Create a login page
c) Create your security check include file
d) Secure your site

There are many different ways you can modify this technique to suit your own needs. Some of these ideas will be listed at the end of this article.

Step 1: Store your data

In order to authenticate your users, you must store their information somewhere. That location can be a flat text file or a database server. In this tutorial, we will use a MySql database. Given that you probably already have a database you wish to use, this article will focus just on one table: tblUsers.

This table will store all of your user information but we will only focus on the fields necessary to this article. The following fields are required:

iUser - This will be a unique ID used in the table.
sEmail - We will use the email address as the login
sPassword - We will need this to authenticate the user
sGUID - This is the field to store the users current session ID
sData - This is where you can store various session information about the user.

To create this table in MySql, execute the following DDL:

CREATE TABLE tblUsers (
iUser int(10) unsigned NOT NULL auto_increment,
sEmail varchar(255) NOT NULL,
sPassword varchar(255) NOT NULL,
sGUID varchar(32),
sData text,
PRIMARY KEY (iUser)
) TYPE=MyISAM;

In the interest of space and time, this article will assume you can build your own "Add User" form and we will use the following DML to add a user for demonstration purposes:

INSERT INTO tblUsers Values
(
Null,
'test@user.com',
password('testpass'),
Null,
Null
)

Note the use of MySql's Password() function. This is a one-way function so you will not be able to "retrieve" the user's password. There are other options you can use besides the Password() function such as a md5 hash or your own cipher. The Null value for the iUser field triggers the auto_number function and will generate a unique ID for us. The user we just created has an email/username of test@user.com and a password of testpass.

Step 2: Create a login page

You will need a way to authenticate your users as they enter the system. You will create a login page in such a manner that it can intercept a user going to any secured page in your system. Once the user has logged in they will be redirected back to the page they were attempting to access.

First, we need a simple HTML form so save the following HTML as Login.php:

<html>
<head><title>Login</title></head>
<body>
<form action="LoginAction.php" method="Post">
Email Address:<br />
<input type="Text" name="psEmail" />
<br />
Password:<br />
<input type="password" name="psPassword" />
<br />
<input type="submit" value="Login" />
<input type="hidden" name="psRefer" value="<? echo($refer) ?>"
</form>
</body>
</html>

The obvious parts of this login page are the email and password. The hidden field psRefer will be a query string variable that is passed to this page, which represents from where the user entered the web site.

Next, we need a page that will actually authenticate the user against the data in the database. If the user is successfully authenticated a GUID will be generated and they will be on their way. If they are NOT authenticated they will be sent back to the login page. The following code should be saved as LoginAction.php:

<?php
// Check if the information has been filled in
if($psEmail == '' || $psPassword == '') {
// No login information
header('Location: Login.php?refer='.urlencode($psRefer));
} else {
// Authenticate user
$hDB = mysql_connect('server', 'user', 'pass');
mysql_select_db('database', $hDB);
$sQuery = "
Select iUser, MD5(UNIX_TIMESTAMP() + iUser + RAND(UNIX_TIMESTAMP())) sGUID
From tblUsers
Where sEmail = '$psEmail'
And sPassword = password('$psPassword')";
$hResult = mysql_query($sQuery, $hDB);
if(mysql_affected_rows($hDB)) {
$aResult = mysql_fetch_row($hResult);
// Update the user record
$sQuery = "
Update tblUsers
Set sGUID = '$aResult[1]'
Where iUser = $aResult[0]";
mysql_query($sQuery, $hDB);
// Set the cookie and redirect
setcookie("session_id", $aResult[1]);
if(!$psRefer) $psRefer = 'index.php';
header('Location: '.$psRefer);
} else {
// Not authenticated
header('Location: Login.php?refer='.urlencode($psRefer));
}
}
?>

The first objective of this code is to verify that a username and password were sent and otherwise return to the login page. This is just some rudimentary protection against some hacking. Next, the code connects to a database and tries to retrieve the user data matching the credentials sent from the Login.php page. If there is no match in the database the user is returned to the login page.

If there is a match the user record is updated with a GUID and a cookie is set on the user's computer. You do not have to use cookies here but this prevents you from having to put the session id on the URL of every page. After the cookie is set, the user is either sent to the referring page or to a default page (in this example: index.php).

To generate the GUID or session ID, you need to generate a unique number and hash it to protect would-be hackers from brute-forcing their way into your application. This article used MySql's built in MD5 function with a formula to help generate a random seed. You can use PHP's hashing functions or any other method of generating random hashes here.

Step 3: Create an include file

Now that you have a login mechanism, you need to create a page that will easily protect any page in your web site by simply including it. To make this "smart" page you just need to check the user's session ID that is stored in their cookie against the database. If there is a match then the user has logged in otherwise they should be redirected to the Login.php page. Here is the PHP code to perform that (call it incSession.php):

<?php
// Check for a cookie, if none got to login page
if(!isset($HTTP_COOKIE_VARS['session_id'])) {
header('Location: Login.php?refer='.urlencode($PHP_SELF.'?'.$HTTP_SERVER_VARS['QUERY_STRING']));
}
// Try to find a match in the database
$sGUID = $HTTP_COOKIE_VARS['session_id'];
$hDB = mysql_connect('server', 'username', 'password');
mysql_select_db('database', $hDB);
$sQuery = "
Select iUser
From tblUsers
Where sGUID = '$sGUID'";
$hResult = mysql_query($sQuery, $hDB);
if(!mysql_affected_rows($hDB)) {
// No match for guid
header('Location: Login.php?refer='.urlencode($PHP_SELF.'?'.$HTTP_SERVER_VARS['QUERY_STRING']));
}
?>

The first part of the code checks to see if there is a cookie set with the session ID otherwise it will redirect the user to the Login.php page. If there is a valid session ID the script will try and match it against the database. If there is not a match the user is redirected to a Login.php page. Otherwise, the user is allowed to continue onto the page they were trying to access. To add this security to a page in your application, simply add the following code to the top of the page:

<?PHP require('incSession.php'); ?>

Now you have secured your application! Once you get over the initial creation of the Login and actions pages you only need to add the one line of code above to secure any page in your web. Here is a list of modifications you can make to the above implementation to make the script even better:

Expiration - You can have the login expire by adding a logged-in date field to tblUsers. You would need to check that date against your "timeout" in incSession.php.

Security Levels - You can add a field to tblUsers to specify the user's security clearence. Then you can compare that value against a variable that you have defined on each secured page. For example you could put the following at the top of your secured page:

<?PHP
$giSecurityLevel = 3;
require('incSession.php');
?>

After that, the script could return the user's security level in incSession.php and compare it against $giSecurityLevel. If the user's level is below the required level the script can redirect them to a "no access" page.

Store/Retrieve Session Data - You can use the sData field to store the user's session information (like a shopping cart, for example) as a formatted string or even XML data. The choice is entirely yours since it is a large text field.

Conclusion

Using the script above will assure that you have a simple and foolproof method of securing your web site. There are many other methods available (PHP sessions, .htaccess, etc.) and each has their strengths and weaknesses. I believe this method to be one of the most portable and easily customized methods available.

Detecting AJAX Request with PHP

Here, I will show you how can detect if a HTTP request was an Ajax request. Ajax requests are performed in JavaScript using the XMLHttpRequest component.

When such a request is made, a HTTP header called X-Requested-With is sent. The corresponding value for this header is XMLHttpRequest. You can access these headers from the PHP superglobal $_SERVER.

PHP renames HTTP request headers so dashes become underscores and all letters are made upper-case. Therefore we can check $_SERVER['X_REQUESTED_WITH'].

Therefore you can use the following code to check if a request is from an Ajax request.

Listing 1 Checking if a request is an Ajax request (listing-1.php)
<?php
$isXmlHttpRequest = array_key_exists('X_REQUESTED_WITH', $_SERVER) &&
$_SERVER['X_REQUESTED_WITH'] == 'XMLHttpRequest';

if ($isXmlHttpRequest) {
// is an Ajax request
}
else {
// is not an Ajax request
}
?>
If you're using Zend_Controller_Front, you can call the the isXmlHttpRequest() method on the request object.

Being able to check if a request is useful to determine what kind of content to send back. For example, if the request is an Ajax request you may want to send back some JSON data, whereas if it's not you may just want to return normal HTML.

In the following listing I demonstrate this. If the request is an Ajax request we sent some JSON data back, otherwise we fall through and output normal HTML.

Listing 2 Outputting JSON data for Ajax requests only (listing-2.php)
<?php
$isXmlHttpRequest = array_key_exists('X_REQUESTED_WITH', $_SERVER) &&
$_SERVER['X_REQUESTED_WITH'] == 'XMLHttpRequest';

if ($isXmlHttpRequest) {
$data = array(
'foo' => 'bar'
);

header('Content-type: application/json');
echo json_encode($data);
exit;
}
?>
<html>
<head><title>Normal page content</title></head>
<body>
<!-- normal page content -->
</body>
</html>

Using Return Codes in PHP


I will show you how to execute a command on your server using system(). I will show you how to check if the command was successful using its return value.

To demonstrate this functionality we'll write a short script restarts your web server. Before restarting the server it will verify the configuration file is valid.

To execute a command we use the system() function. This function accepts as its first argument the command to execute, while the second argument is a variable you pass by reference that the return value is written to.
Note: You can also use functions such as exec() or passthru() if you need to access output from the program, but to keep things simple we'll ignore these functions.

The following listing shows how you to call system().
Listing 1 Accessing and outputting the return value from system() (listing-1.php)

<?php
system('/path/to/someCommand', $retval);
echo "Return value: " . $retval;
?>

If a command-line program has been written correctly, it will exit with a status code of 0 when the program executes correctly, or it will exit with a non-zero value when something does not work correctly.

The following listing shows a basic check of the return value. The specific error that has occurred will depend on the command being run.
Listing 2 Checking the return value and acting accordingly (listing-2.php)

<?php
system('/path/to/someCommand', $retval);

if ($retval == 0) {
echo "Executed correctly\n";
}
else {
echo "Some error occurred: " . $retval;
}
?>

To demonstrate this, we'll write a short script that calls makes use of the apachectl program. This is used to control an Apache installation (start / stop / restart the server). If you run this command with an argument of configtest it will tell you if the configuration is valid. If you run it with an argument of graceful it will restart the server (gracefully - that is, it will complete any active requests).

When you run apachectl configtest it will tell you if an error occurs, but additionally, it will exit with a code of 8 (you can see this documented inside the apachectl script).

Therefore, you can run this command and check if the configuration file is valid. If it is, we'll restart the server, if not, we won't. The following listing demonstrates this.
Listing 3 Restarting your Apache server if the configuration is valid (listing-3.php)

<?php
$ctl = '/usr/local/apache/bin/apachectl';

system($ctl . ' configtest', $retval);

if ($retval == 0) {
system($ctl . ' graceful');
}
else {
echo "Configuration error, unable to restart\n";
exit($retval);
}
?>

In this script we chained the return value. That is, when an error occurred we also exited with that return code. That way, if yet another script uses our PHP script they can also check the error code if required.

That's all there is to it! You could extend this script by checking the return value of the second command also, since this call can also fail.

Improving Web Performance from Page Components

On a web page images, flash, style sheets and scripts are some of the components that take time to load. For increasing the site load time, we might have to keep the site simple and reduce the number of web components on a page. The Http request/replies have to be kept at a minimum for optimum web performance.

The web page design needs to be simple by reducing the number of page components that take time to load. CSS sprites are one of the most preferred methods that reduce the number of image requests.

Response times are often impacted by user's proximity on web servers. When looked upon content for a solution, deploying content to server across multiple geographies will make the pages load faster. This can also be made unique to geography, looking upon the local market for the product or service, as this would definitely boost online businesses locally for their geographies.
Changing the architecture of the site can be a daunting task, synchronizing session state and replicating the database transactions across al the server locations. On an average, 80 to 90% of the time is spent on loading the components of the page. Its always a god idea to disperse static content rather then redesigning your site applications architecture. The front end engineers that care about web performance want a page to load progressively as soon as possible. This is very essential for the users who are looking out for a lot of content are on very low internet speeds.

Monitoring website applications in terms of performance should be focused in order to have optimum performing site. Web application monitoring solutions should be used to have comprehensive monitoring of web applications. Web performance is directly dependent on monitoring the website with different aspects in mind regarding all the components used on the website.

Resolving Error 8906 in MS SQL


In MS SQL Server database, a PFS (Page Free Space) page has one byte for each of the pages existing in the file interval it maps. This byte contains a bit that indicates that the associated page is a mixed page. An IAM page includes a mixed page array, which is an array of eight page IDs, to keep the mixed pages that have been allocated to the index. In some cases, when the database goes corrupted, the page containing 'mixed page' bit is not recognized correctly. Thus, you can detect such specific cases of database corruption and, take corrective measures for MS SQL Repair.

Most of the SQL database corruption problems can be analyzed and detected by running DBCC CHECKDB command. Let's consider the below error message, which typically appears when the discussed problem occurs. When you run DBCC CHECKDB command to check the integrity of database, following error might pop up:


Server: Msg 8906, Level 16, State 1, Line 0
Page P_ID in database ID DB_ID is allocated in the SGAM SGAM_P_ID and PFS PFS_P_ID, but was not allocated in any IAM. PFS flags 'PFS_FLAGS'.

Cause

Error 8906 is most likely to occur when a page with 'mixed page' bit set up in PFS byte has not been detected as an IAM page or in a mixed page array of an IAM page, which indicates database corruption.

Solution

If you encounter error 8906 after running DBCC CHECKDB on your SQL Server database, apply the below measures to solve it:

Run hardware diagnostics to isolate hardware-related problems. Corrupted hardware components are known to cause these issues if database corruption persists.
Restore the database from last good backup available.

If no clean backup is available, run DBCC CHECKDB without any repair clause to know the extent of damage and required SQL Repair clause. Again run DBCC CHECKDB command with the recommended repair clause. Make sure to backup your database before executing the repair command, in order to avoid post-crash results.
Use a third-party SQL Repair utility, in case DBCC CHECKDB doesn't work.


For best results, it is recommended to use Stellar Phoenix SQL Recovery software. Designed to run powerful and safe scanning algorithms, this SQL Repair utility can restore all database objects in a simple way. The application supports MS SQL Server 2008, 2005, and 2000.