How can I be sure my page is secured ?
Before outputting anything, check that the visitor is authorized to view the page. If not, redirect them to a login page, including the URL of the protected page as a query parameter so the login script can redirect back to the original page. If you do it right, redirection should also prevent your problem.
For example, at the start of every page that needs protection put:
PHP:
<?php
include_once('../init.php');
include('auth.php');
protect(...);
?>
where the argument to
protect() can be nothing (to give everyone access), an array of groups, or an array of groups & an array of users.
In include/auth.php (among other functions):
PHP:
/* login(): Attempt to login the user (if necessary).
returns: true on success, false if login fails (user doesn't have a login session
& can't get a login session). If a login session already exists, login is successful.
*/
function login() {
if (! isset($_SESSION['user'])) {
...
} else {
if ($_SESSION['ip'] != $_SERVER['REMOTE_ADDR']) {
/* Session hijack. Don't logout, because this will destroy the
* session for the real user.
*/
destroy_login_cookie();
return False;
}
return True;
}
}
/* logout(): Destroys the session to logout */
function logout() {
$_SESSION = array();
if (ini_get("session.use_cookies")) {
destroy_login_cookie();
}
session_destroy();
}
/* authed: return true if user is authorized to view page, which is determined
by checking if user is member of one of the specified groups. Alternative is
to store authorization information (page => authorized users & groups) somewhere
and refer to that.
Params--
$groups: array of group names that are allowed access
$users: array of user names that are allowed access
*/
function authed($groups=array('everyone'), $users=array()) {
return login()
&& ( $_SESSION['user']->isInGroup($groups)
|| $_SESSION['user']->isIn($users));
}
function protect($groups=array('everyone'), $users=array()) {
if (! authed($groups, $users)) {
header("Location: $_SERVER[APP_ROOT]/login?redir=" . urlencode($_SERVER[REQUEST_URI]));
exit();
}
}
function destroy_login_cookie() {
$params = session_get_cookie_params();
setcookie(session_name(), '', 1 /* expire at 1 second past epoch */,
$params["path"], $params["domain"],
$params["secure"], $params["httponly"]
);
}
You can also place the above functions in a class to allow the authorization system to be easily changed.
PHP:
interface Authorizer {
public function login();
public function logout();
public function authed($groups=array('everyone'), $users=array());
public function protect($groups=array('everyone'), $users=array());
}
init.php sets up the include path and starts the session:
PHP:
<?php
if (!function_exists('addToIncludePath')) {
function addToIncludePath($path) {
$currIncPath = ini_get('include_path');
if (!preg_match('#(^|:)'.preg_quote($path, '#').'(:|$)#', $currIncPath)) {
set_include_path(get_include_path() . ':' . $path);
}
}
}
$_SERVER['APP_BASE'] = dirname(__FILE__);
addToIncludePath($_SERVER['APP_BASE'] . '/include');
/* add other directories to include path, if any */
...
/* include configuration settings */
include('conf.php');
$_SERVER['APP_ROOT'] = $conf['app_root']; // defined in include/conf.php
/* include any classes that might define objects be stored in $_SESSION before calling session_start() */
include_once('User.php');
...
start_session();
...
?>
Much needs to be filled in, such as the
login() function, the
User class and the login page. You can work in login/logout forms and actions as you see fit. The way you check for a user's membership in a group will need to be rewritten if users don't track that information.
I have not used .htaccess file, ignoring how it works exatly ; should I write something in it ?
There are two things you can configure in .htaccess that might apply:
mod_auth (to use the web server for authentication, which won't be compatible with your user system) and
mod_access (to protect files and folders from being accessed by anyone). The latter will be of particular use to prevent visitors from accessing page fragments & included scripts. In the "include" directory, as well as any directories containing views, actions &c., put an .htaccess with:
Code:
Deny from all
Order allow, deny
This will deny all direct access via HTTP requests, though scripts can still access the files locally.