Use global request tokens and automatically protect all POST requests

release-0.6
thomascube 16 years ago
parent 61e96cd1f9
commit 5499336fef

@ -2,7 +2,7 @@
/* /*
+-------------------------------------------------------------------------+ +-------------------------------------------------------------------------+
| RoundCube Webmail IMAP Client | | RoundCube Webmail IMAP Client |
| Version 0.3-20090702 | | Version 0.3-20090721 |
| | | |
| Copyright (C) 2005-2009, RoundCube Dev. - Switzerland | | Copyright (C) 2005-2009, RoundCube Dev. - Switzerland |
| | | |
@ -143,11 +143,16 @@ else if ($RCMAIL->action != 'login' && $_SESSION['user_id'] && $RCMAIL->action !
// check client X-header to verify request origin // check client X-header to verify request origin
if ($OUTPUT->ajax_call) { if ($OUTPUT->ajax_call) {
if (!$RCMAIL->config->get('devel_mode') && !rc_request_header('X-RoundCube-Referer')) { if (!$RCMAIL->config->get('devel_mode') && rc_request_header('X-RoundCube-Request') != $RCMAIL->get_request_token()) {
header('HTTP/1.1 404 Not Found'); header('HTTP/1.1 404 Not Found');
die("Invalid Request"); die("Invalid Request");
} }
} }
// check request token in POST form submissions
else if (!empty($_POST) && !$RCMAIL->check_request()) {
$OUTPUT->show_message('invalidrequest', 'error');
$OUTPUT->send($RCMAIL->task);
}
// not logged in -> show login page // not logged in -> show login page

@ -872,33 +872,29 @@ class rcmail
/** /**
* Generate a unique token to be used in a form request * Generate a unique token to be used in a form request
* *
* @param string Request identifier
* @return string The request token * @return string The request token
*/ */
public function get_request_token($key) public function get_request_token()
{ {
if (!$this->request_tokens[$key]) $key = $this->task;
$_SESSION['request_tokens'][$key] = $this->request_tokens[$key] = md5(uniqid($key . rand(), true));
return $this->request_tokens[$key]; if (!$_SESSION['request_tokens'][$key])
$_SESSION['request_tokens'][$key] = md5(uniqid($key . rand(), true));
return $_SESSION['request_tokens'][$key];
} }
/** /**
* Check if the current request contains a valid token * Check if the current request contains a valid token
* *
* @param string Request identifier * @param int Request method
* @return boolean True if request token is valid false if not * @return boolean True if request token is valid false if not
*/ */
public function check_request($key, $mode = RCUBE_INPUT_POST) public function check_request($mode = RCUBE_INPUT_POST)
{ {
$token = get_input_value('_token', $mode); $token = get_input_value('_token', $mode);
$valid = !(empty($token) || $_SESSION['request_tokens'][$key] != $token); return !empty($token) && $_SESSION['request_tokens'][$this->task] == $token;
if ($valid)
unset($_SESSION['request_tokens'][$key]);
return $valid;
} }

@ -59,6 +59,7 @@ class rcube_template extends rcube_html_page
//$this->framed = $framed; //$this->framed = $framed;
$this->set_env('task', $task); $this->set_env('task', $task);
$this->set_env('request_token', $this->app->get_request_token());
// load the correct skin (in case user-defined) // load the correct skin (in case user-defined)
$this->set_skin($this->config['skin']); $this->set_skin($this->config['skin']);
@ -326,6 +327,9 @@ class rcube_template extends rcube_html_page
$js .= $this->get_js_commands() . ($this->framed ? ' }' : ''); $js .= $this->get_js_commands() . ($this->framed ? ' }' : '');
$this->add_script($js, 'head_top'); $this->add_script($js, 'head_top');
// make sure all <form> tags have a valid request token
$template = preg_replace_callback('/<form\s+([^>]+)>/Ui', array($this, 'alter_form_tag'), $template);
// call super method // call super method
parent::write($template, $this->config['skin_path']); parent::write($template, $this->config['skin_path']);
} }
@ -518,6 +522,23 @@ class rcube_template extends rcube_html_page
} }
/**
*
*/
private function alter_form_tag($matches)
{
$out = $matches[0];
$attrib = parse_attrib_string($matches[1]);
if (strtolower($attrib['method']) == 'post') {
$hidden = new html_hiddenfield(array('name' => '_token', 'value' => $this->app->get_request_token()));
$out .= "\n" . $hidden->show();
}
return $out;
}
/** /**
* Parses expression and replaces variables * Parses expression and replaces variables
* *
@ -957,10 +978,6 @@ class rcube_template extends rcube_html_page
$hidden->add(array('name' => '_action', 'value' => $attrib['action'])); $hidden->add(array('name' => '_action', 'value' => $attrib['action']));
} }
// generate request token
$request_key = $attrib['request'] ? $attrib['request'] : $attrib['action'];
$hidden->add(array('name' => '_token', 'value' => $this->app->get_request_token($request_key)));
unset($attrib['task'], $attrib['request']); unset($attrib['task'], $attrib['request']);
$attrib['action'] = './'; $attrib['action'] = './';

@ -55,7 +55,7 @@ function rcube_webmail()
// set jQuery ajax options // set jQuery ajax options
jQuery.ajaxSetup({ cache:false, jQuery.ajaxSetup({ cache:false,
error:function(request, status, err){ ref.http_error(request, status, err); }, error:function(request, status, err){ ref.http_error(request, status, err); },
beforeSend:function(xmlhttp){ xmlhttp.setRequestHeader('X-RoundCube-Referer', bw.get_cookie('roundcube_sessid')); } beforeSend:function(xmlhttp){ xmlhttp.setRequestHeader('X-RoundCube-Request', ref.env.request_token); }
}); });
// set environment variable(s) // set environment variable(s)

@ -5,7 +5,7 @@
| program/steps/addressbook/save.inc | | program/steps/addressbook/save.inc |
| | | |
| This file is part of the RoundCube Webmail client | | This file is part of the RoundCube Webmail client |
| Copyright (C) 2005-2007, RoundCube Dev. - Switzerland | | Copyright (C) 2005-2009, RoundCube Dev. - Switzerland |
| Licensed under the GNU GPL | | Licensed under the GNU GPL |
| | | |
| PURPOSE: | | PURPOSE: |
@ -22,14 +22,6 @@
$cid = get_input_value('_cid', RCUBE_INPUT_POST); $cid = get_input_value('_cid', RCUBE_INPUT_POST);
$return_action = empty($cid) ? 'add' : 'show'; $return_action = empty($cid) ? 'add' : 'show';
// check request token and exit if invalid
if (!$RCMAIL->check_request('save.'.intval($cid), RCUBE_INPUT_POST))
{
$OUTPUT->show_message('invalidrequest', 'error');
rcmail_overwrite_action($return_action);
return;
}
// cannot edit record // cannot edit record
if ($CONTACTS->readonly) if ($CONTACTS->readonly)
{ {

@ -5,7 +5,7 @@
| program/steps/settings/save_identity.inc | | program/steps/settings/save_identity.inc |
| | | |
| This file is part of the RoundCube Webmail client | | This file is part of the RoundCube Webmail client |
| Copyright (C) 2005-2007, RoundCube Dev. - Switzerland | | Copyright (C) 2005-2009, RoundCube Dev. - Switzerland |
| Licensed under the GNU GPL | | Licensed under the GNU GPL |
| | | |
| PURPOSE: | | PURPOSE: |
@ -26,12 +26,6 @@ $a_html_cols = array('signature');
$a_boolean_cols = array('standard', 'html_signature'); $a_boolean_cols = array('standard', 'html_signature');
$updated = $default_id = false; $updated = $default_id = false;
// check request token
if (!$RCMAIL->check_request('save-identity.'.intval(get_input_value('_iid', RCUBE_INPUT_POST)), RCUBE_INPUT_POST)) {
$OUTPUT->show_message('invalidrequest', 'error');
rcmail_overwrite_action('identities');
return;
}
// check input // check input
if (empty($_POST['_name']) || (empty($_POST['_email']) && IDENTITIES_LEVEL != 1 && IDENTITIES_LEVEL != 3)) if (empty($_POST['_name']) || (empty($_POST['_email']) && IDENTITIES_LEVEL != 1 && IDENTITIES_LEVEL != 3))
{ {

@ -5,7 +5,7 @@
| program/steps/settings/save_prefs.inc | | program/steps/settings/save_prefs.inc |
| | | |
| This file is part of the RoundCube Webmail client | | This file is part of the RoundCube Webmail client |
| Copyright (C) 2005-2007, RoundCube Dev. - Switzerland | | Copyright (C) 2005-2009, RoundCube Dev. - Switzerland |
| Licensed under the GNU GPL | | Licensed under the GNU GPL |
| | | |
| PURPOSE: | | PURPOSE: |
@ -19,13 +19,6 @@
*/ */
// check request token and exit if invalid
if (!$RCMAIL->check_request('save-prefs', RCUBE_INPUT_POST)) {
$OUTPUT->show_message('invalidrequest', 'error');
rcmail_overwrite_action('preferences');
return;
}
$a_user_prefs = array( $a_user_prefs = array(
'language' => isset($_POST['_language']) ? get_input_value('_language', RCUBE_INPUT_POST) : $CONFIG['language'], 'language' => isset($_POST['_language']) ? get_input_value('_language', RCUBE_INPUT_POST) : $CONFIG['language'],
'timezone' => isset($_POST['_timezone']) ? (is_numeric($_POST['_timezone']) ? floatval($_POST['_timezone']) : get_input_value('_timezone', RCUBE_INPUT_POST)) : $CONFIG['timezone'], 'timezone' => isset($_POST['_timezone']) ? (is_numeric($_POST['_timezone']) ? floatval($_POST['_timezone']) : get_input_value('_timezone', RCUBE_INPUT_POST)) : $CONFIG['timezone'],

Loading…
Cancel
Save