From 5499336feff22f682448dd99cc00a9b36701fcd1 Mon Sep 17 00:00:00 2001 From: thomascube <thomas@roundcube.net> Date: Tue, 21 Jul 2009 12:02:33 -0400 Subject: [PATCH] Use global request tokens and automatically protect all POST requests --- index.php | 9 +++- program/steps/addressbook/save.inc | 10 ---- program/include/rcmail.php | 22 ++++------ program/steps/settings/save_identity.inc | 8 --- program/include/rcube_template.php | 27 +++++++++++-- program/js/app.js | 2 program/steps/settings/save_prefs.inc | 9 ---- 7 files changed, 42 insertions(+), 45 deletions(-) diff --git a/index.php b/index.php index 2767277..c5a1049 100644 --- a/index.php +++ b/index.php @@ -2,7 +2,7 @@ /* +-------------------------------------------------------------------------+ | RoundCube Webmail IMAP Client | - | Version 0.3-20090702 | + | Version 0.3-20090721 | | | | Copyright (C) 2005-2009, RoundCube Dev. - Switzerland | | | @@ -143,11 +143,16 @@ // check client X-header to verify request origin 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'); 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 diff --git a/program/include/rcmail.php b/program/include/rcmail.php index a508e17..39edee4 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -872,33 +872,29 @@ /** * Generate a unique token to be used in a form request * - * @param string Request identifier * @return string The request token */ - public function get_request_token($key) + public function get_request_token() { - if (!$this->request_tokens[$key]) - $_SESSION['request_tokens'][$key] = $this->request_tokens[$key] = md5(uniqid($key . rand(), true)); + $key = $this->task; - 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 * - * @param string Request identifier + * @param int Request method * @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); - $valid = !(empty($token) || $_SESSION['request_tokens'][$key] != $token); - - if ($valid) - unset($_SESSION['request_tokens'][$key]); - - return $valid; + return !empty($token) && $_SESSION['request_tokens'][$this->task] == $token; } diff --git a/program/include/rcube_template.php b/program/include/rcube_template.php index caf385a..0947944 100755 --- a/program/include/rcube_template.php +++ b/program/include/rcube_template.php @@ -59,6 +59,7 @@ //$this->framed = $framed; $this->set_env('task', $task); + $this->set_env('request_token', $this->app->get_request_token()); // load the correct skin (in case user-defined) $this->set_skin($this->config['skin']); @@ -325,6 +326,9 @@ $js = $this->framed ? "if(window.parent) {\n" : ''; $js .= $this->get_js_commands() . ($this->framed ? ' }' : ''); $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 parent::write($template, $this->config['skin_path']); @@ -514,7 +518,24 @@ */ private function check_condition($condition) { - return eval("return (".$this->parse_expression($condition).");"); + return eval("return (".$this->parse_expression($condition).");"); + } + + + /** + * + */ + 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; } @@ -956,10 +977,6 @@ if ($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']); $attrib['action'] = './'; diff --git a/program/js/app.js b/program/js/app.js index 332ee87..4ce3546 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -55,7 +55,7 @@ // set jQuery ajax options jQuery.ajaxSetup({ cache:false, 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) diff --git a/program/steps/addressbook/save.inc b/program/steps/addressbook/save.inc index 45cb638..639e0f2 100644 --- a/program/steps/addressbook/save.inc +++ b/program/steps/addressbook/save.inc @@ -5,7 +5,7 @@ | program/steps/addressbook/save.inc | | | | 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 | | | | PURPOSE: | @@ -21,14 +21,6 @@ $cid = get_input_value('_cid', RCUBE_INPUT_POST); $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 if ($CONTACTS->readonly) diff --git a/program/steps/settings/save_identity.inc b/program/steps/settings/save_identity.inc index 86ff263..d36114c 100644 --- a/program/steps/settings/save_identity.inc +++ b/program/steps/settings/save_identity.inc @@ -5,7 +5,7 @@ | program/steps/settings/save_identity.inc | | | | 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 | | | | PURPOSE: | @@ -26,12 +26,6 @@ $a_boolean_cols = array('standard', 'html_signature'); $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 if (empty($_POST['_name']) || (empty($_POST['_email']) && IDENTITIES_LEVEL != 1 && IDENTITIES_LEVEL != 3)) { diff --git a/program/steps/settings/save_prefs.inc b/program/steps/settings/save_prefs.inc index 7444a8b..8430ffd 100644 --- a/program/steps/settings/save_prefs.inc +++ b/program/steps/settings/save_prefs.inc @@ -5,7 +5,7 @@ | program/steps/settings/save_prefs.inc | | | | 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 | | | | PURPOSE: | @@ -18,13 +18,6 @@ $Id$ */ - -// 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( 'language' => isset($_POST['_language']) ? get_input_value('_language', RCUBE_INPUT_POST) : $CONFIG['language'], -- Gitblit v1.9.1