thomascube
2009-07-21 5499336feff22f682448dd99cc00a9b36701fcd1
Use global request tokens and automatically protect all POST requests

7 files modified
87 ■■■■ changed files
index.php 9 ●●●● patch | view | raw | blame | history
program/include/rcmail.php 22 ●●●●● patch | view | raw | blame | history
program/include/rcube_template.php 27 ●●●● patch | view | raw | blame | history
program/js/app.js 2 ●●● patch | view | raw | blame | history
program/steps/addressbook/save.inc 10 ●●●● patch | view | raw | blame | history
program/steps/settings/save_identity.inc 8 ●●●● patch | view | raw | blame | history
program/steps/settings/save_prefs.inc 9 ●●●● patch | view | raw | blame | history
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
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;
  }
  
  
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'] = './';
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)
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)
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))
  {
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'],