--- securepages.module.orig 2007-02-03 11:06:42.000000000 -0600 +++ securepages.module 2007-02-12 15:59:27.000000000 -0600 @@ -4,6 +4,13 @@ /** * Implementation of hook_help() */ + +// Include $base_path in SECUREPAGES_SESSID so a user can be logged in +// to more than one Drupal site per domain. +global $base_path; +define('SECUREPAGES_SESSID', + 'SECUREPAGES_SESSID_'.preg_replace('/[^a-zA-Z0-9_]/', '_', $base_path)); + function securepages_help($section) { switch ($section) { case 'admin/modules#description': @@ -19,6 +26,12 @@ function securepages_init() { global $base_url; $path = $_GET['q']; + + // logging out is always allowed + if ($path === 'logout') { + return; + } + $page_match = securepages_match($path); if ($_POST) { @@ -35,6 +48,41 @@ function securepages_init() { if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') { $base_url = str_replace('http://', 'https://', $base_url); } + + if (variable_get('securepages_prevent_hijack', FALSE) && + $path != 'admin/settings/securepages' && + ! securepages_match('user')) { + drupal_set_message('WARNING! Secure Pages is set to prevent hijacked '. + 'sessions from accessing SSL pages but the user login '. + 'page is not set to be secured. Fix your '. + l('Secure Pages settings', 'admin/settings/securepages') + .' now; make sure user* is secure.'); + } + + // If this is and is supposed to be a secure page, and a user has + // logged in, verify that the secure cookie (set in securepages_user + // hook below) matching the secure token in $_SESSION is present. + global $user; + if ($user->uid > 0 && $page_match && $_SERVER['HTTPS'] && + variable_get('securepages_prevent_hijack', FALSE)) { + if (is_null($_COOKIE[SECUREPAGES_SESSID]) || + $_COOKIE[SECUREPAGES_SESSID] !== $_SESSION[SECUREPAGES_SESSID]) { + watchdog('security', + t('Session hijack attempt detected for user %user!', + array('%user' => theme('placeholder', $user->name)))); + + menu_set_active_item(''); + drupal_set_title(t('Access denied by Secure Pages module')); + $return = t('

The Secure Pages module has detected an invalid '. + 'session access attempt. Please '. + l('log in again', 'logout', array(), + 'destination=user/login') . + '.'); + print theme('page', $return); + module_invoke_all('exit', $url); + exit; + } + } } /** @@ -47,6 +95,12 @@ function securepages_settings() { '#return_value' => TRUE, '#default_value' => variable_get('securepages_switch', FALSE), ); + $form['securepages_prevent_hijack'] = array( + '#type' => 'checkbox', + '#title' => t('Prevent hijacked sessions from accessing SSL pages'), + '#return_value' => TRUE, + '#default_value' => variable_get('securepages_prevent_hijack', FALSE), + ); $form['securepages_secure'] = array( '#type' => 'radios', '#title' => t('Pages which will be be secure'), @@ -90,6 +144,30 @@ function securepages_form_alter($form_id } /** + * Implementation of hook_user() + */ +function securepages_user($op, &$edit, &$user, $category = NULL) { + switch ($op) { + case 'login': + if (variable_get('securepages_prevent_hijack', FALSE)) { + if (! $_SERVER['HTTPS']) { + // Admin asked us to prevent hijacks but we have a non-secure login. + watchdog('security', t('Secure Pages detected non-SSL login '. + 'with hijack-prevention enabled.')); + } + + // The user has just logged in. Set a secure cookie (that will + // only be returned to SSL-protected pages) containing a + // non-guessable token, and store that token in the $_SESSION. + $tok = md5(mt_rand() . $edit['pass'] . mt_rand()); + $_SESSION[SECUREPAGES_SESSID] = "$tok"; + setcookie(SECUREPAGES_SESSID, $tok, NULL, '/', NULL, 1); + } + break; + } +} + +/** * securepage_goto() * * Redirects the current page to the secure or insecure version.