Use global request tokens and automatically protect all POST requests
| | |
| | | /* |
| | | +-------------------------------------------------------------------------+ |
| | | | RoundCube Webmail IMAP Client | |
| | | | Version 0.3-20090702 | |
| | | | Version 0.3-20090721 | |
| | | | | |
| | | | Copyright (C) 2005-2009, RoundCube Dev. - Switzerland | |
| | | | | |
| | |
| | | |
| | | // 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 |
| | |
| | | /** |
| | | * 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; |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | //$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']); |
| | |
| | | $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']); |
| | | } |
| | |
| | | private function check_condition($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; |
| | | } |
| | | |
| | | |
| | |
| | | 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'] = './'; |
| | |
| | | // 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) |
| | |
| | | | 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: | |
| | |
| | | |
| | | $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) |
| | |
| | | | 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: | |
| | |
| | | $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)) |
| | | { |
| | |
| | | | 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: | |
| | |
| | | $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'], |