From a77cf2292b1b5e010172b572f618aef78795456b Mon Sep 17 00:00:00 2001
From: thomascube <thomas@roundcube.net>
Date: Tue, 08 Feb 2011 03:13:06 -0500
Subject: [PATCH] Add optional referer check to prevent CSRF in GET requests

---
 CHANGELOG                     |    1 +
 index.php                     |    8 ++++++++
 program/steps/utils/error.inc |    9 ++++++++-
 program/include/main.inc      |   15 ++++++++++++++-
 config/main.inc.php.dist      |    3 +++
 5 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 2a7cdfb..9a008e9 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
 CHANGELOG Roundcube Webmail
 ===========================
 
+- Security: add optional referer check to prevent CSRF in GET requests
 - Fix email_dns_check setting not used for identities/contacts (#1487740)
 - Fix ICANN example addresses doesn't validate (#1487742)
 - Security: protect login form submission from CSRF
diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist
index 7dfca7a..36c5277 100644
--- a/config/main.inc.php.dist
+++ b/config/main.inc.php.dist
@@ -212,6 +212,9 @@
 // check client IP in session athorization
 $rcmail_config['ip_check'] = false;
 
+// check referer of incoming requests
+$rcmail_config['referer_check'] = false;
+
 // this key is used to encrypt the users imap password which is stored
 // in the session record (and the client cookie if remember password is enabled).
 // please provide a string of exactly 24 chars.
diff --git a/index.php b/index.php
index bf38874..f50cf2b 100644
--- a/index.php
+++ b/index.php
@@ -190,6 +190,14 @@
     $OUTPUT->show_message('invalidrequest', 'error');
     $OUTPUT->send($RCMAIL->task);
   }
+
+  // check referer if configured
+  if (!$request_check_whitelist[$RCMAIL->action] && $RCMAIL->config->get('referer_check') && !rcube_check_referer()) {
+    raise_error(array(
+      'code' => 403,
+      'type' => 'php',
+      'message' => "Referer check failed"), true, true);
+  }
 }
 
 // handle special actions
diff --git a/program/include/main.inc b/program/include/main.inc
index 155f4af..35f9ddc 100644
--- a/program/include/main.inc
+++ b/program/include/main.inc
@@ -5,7 +5,7 @@
  | program/include/main.inc                                              |
  |                                                                       |
  | This file is part of the Roundcube Webmail client                     |
- | Copyright (C) 2005-2009, The Roundcube Dev Team                       |
+ | Copyright (C) 2005-2011, The Roundcube Dev Team                       |
  | Licensed under the GNU GPL                                            |
  |                                                                       |
  | PURPOSE:                                                              |
@@ -1265,6 +1265,19 @@
 
 
 /**
+ * Check whether the HTTP referer matches the current request
+ *
+ * @return boolean True if referer is the same host+path, false if not
+ */
+function rcube_check_referer()
+{
+  $uri = parse_url($_SERVER['REQUEST_URI']);
+  $referer = parse_url(rc_request_header('Referer'));
+  return $referer['host'] == rc_request_header('Host') && $referer['path'] == $uri['path'];
+}
+
+
+/**
  * @access private
  * @return mixed
  */
diff --git a/program/steps/utils/error.inc b/program/steps/utils/error.inc
index 422827a..8b04969 100644
--- a/program/steps/utils/error.inc
+++ b/program/steps/utils/error.inc
@@ -5,7 +5,7 @@
  | program/steps/utils/error.inc                                         |
  |                                                                       |
  | This file is part of the Roundcube Webmail client                     |
- | Copyright (C) 2005-2010, The Roundcube Dev Team                       |
+ | Copyright (C) 2005-2011, The Roundcube Dev Team                       |
  | Licensed under the GNU GPL                                            |
  |                                                                       |
  | PURPOSE:                                                              |
@@ -47,6 +47,13 @@
                    "Please contact your server-administrator.";
 }
 
+// forbidden due to request check
+else if ($ERROR_CODE==403) {
+  $__error_title = "REQUEST CHECK FAILED";
+  $__error_text  = "Access to this service was denied due to failing security checks!<br />\n".
+                   "Please contact your server-administrator.";
+}
+
 // failed request (wrong step in URL)
 else if ($ERROR_CODE==404) {
   $__error_title = "REQUEST FAILED/FILE NOT FOUND";

--
Gitblit v1.9.1