diff options
-rw-r--r-- | engine/lib/actions.php | 83 | ||||
-rw-r--r-- | languages/en.php | 9 | ||||
-rw-r--r-- | views/default/input/button.php | 2 | ||||
-rw-r--r-- | views/default/input/form.php | 17 |
4 files changed, 104 insertions, 7 deletions
diff --git a/engine/lib/actions.php b/engine/lib/actions.php index 682e13b55..0779e5d6a 100644 --- a/engine/lib/actions.php +++ b/engine/lib/actions.php @@ -107,6 +107,89 @@ function actions_init($event, $object_type, $object) {
register_action("error");
return true;
+ } + + /** + * Action gatekeeper. + * This function verifies form input for security features (like a generated token), and forwards + * the page if they are invalid. + * + * Place at the head of actions. + */ + function action_gatekeeper() + { + $token = get_input('__elgg_token'); + $action = get_input('__elgg_action'); + $ts = get_input('__elgg_ts'); + $session_id = session_id(); + + if (($token) && ($action) && ($ts) && ($session_id)) + { + // generate token, check with input and forward if invalid + $generated_token = generate_action_token($action, $ts); + + // Validate token + if (strcmp($token, $generated_token)==0) + { + + // TODO: Validate time to ensure its not crazy + + + return true; + } + else + register_error(elgg_echo('actiongatekeeper:tokeninvalid')); + } + else + register_error(elgg_echo('actiongatekeeper:missingfields')); + + forward(); + exit; + } + + /** + * Generate a token for the current user suitable for being placed in a hidden field in action forms. + * + * @param string $action The action being called + * @param int $timestamp Unix timestamp + */ + function generate_action_token($action, $timestamp) + { + // Get input values + $site_secret = get_site_secret(); + + // Current session id + $session_id = session_id(); + + if (($site_secret) && ($session_id)) + return md5($site_secret.$action.$timestamp.$session_id); + + return false; + } + + /** + * Initialise the site secret. + * + */ + function init_site_secret() + { + $secret = md5(rand().microtime()); + if (datalist_set('__site_secret__', $secret)) + return $secret; + + return false; + } + + /** + * Retrieve the site secret. + * + */ + function get_site_secret() + { + $secret = datalist_get('__site_secret__'); + if (!$secret) $secret = init_site_secret(); + + return $secret; }
// Register some actions ***************************************************
diff --git a/languages/en.php b/languages/en.php index 787ec58e3..f51f9128c 100644 --- a/languages/en.php +++ b/languages/en.php @@ -697,7 +697,14 @@ You cannot reply to this email.", 'entity:default:missingsupport:popup' => 'This entity cannot be displayed correctly. This may be because it requires support provided by a plugin that is no longer installed.',
'entity:delete:success' => 'Entity %s has been deleted',
- 'entity:delete:fail' => 'Entity %s could not be deleted',
+ 'entity:delete:fail' => 'Entity %s could not be deleted', + + + /** + * Action gatekeeper + */ + 'actiongatekeeper:missingfields' => 'Form is missing __action, __token or __ts fields', + 'actiongatekeeper:tokeninvalid' => 'Token provided by form does not match that generated by server.',
/**
* Languages according to ISO 639-1
diff --git a/views/default/input/button.php b/views/default/input/button.php index 115324533..2249158e6 100644 --- a/views/default/input/button.php +++ b/views/default/input/button.php @@ -35,4 +35,4 @@ $src = $vars['src']; if (strpos($src,$CONFIG->wwwroot)===false) $src = ""; // blank src if trying to access an offsite image. ?> -<input type="<?php echo $type; ?>" class="<?php echo $type; ?>_button" <?php echo $vars['js']; ?> value="<?php $value; ?>" src="<?php echo $src; ?>" />
\ No newline at end of file +<input type="<?php echo $type; ?>" class="<?php echo $type; ?>_button" <?php echo $vars['js']; ?> value="<?php echo $value; ?>" src="<?php echo $src; ?>" />
\ No newline at end of file diff --git a/views/default/input/form.php b/views/default/input/form.php index 1f15b046f..5e4c7b001 100644 --- a/views/default/input/form.php +++ b/views/default/input/form.php @@ -17,15 +17,22 @@ * @uses $vars['action'] URL of the action being called * */ - -$body = $vars['body']; -$action = $vars['action']; -$enctype = $vars['enctype']; -$method = $vars['method']; if (!$method) $method = 'POST'; + + $body = $vars['body']; + $action = $vars['action']; + $enctype = $vars['enctype']; + $method = $vars['method']; if (!$method) $method = 'POST'; // TODO: Token generation + // Generate a security header + $ts = time(); + $token = generate_action_token($action, $ts); + $security_header = elgg_view('input/hidden', array('internalname' => '__elgg_token', 'value' => $token)); + $security_header .= elgg_view('input/hidden', array('internalname' => '__elgg_action', 'value' => $action)); + $security_header .= elgg_view('input/hidden', array('internalname' => '__elgg_ts', 'value' => $ts)); ?> <form action="<?php echo $action; ?>" method="<?php echo $method; ?>" <?php if ($enctype!="") echo "enctype=\"$enctype\""; ?>> +<?php echo $security_header; ?> <?php echo $body; ?> </form>
\ No newline at end of file |