summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Dolgov <[email protected]>2011-12-26 12:02:52 +0400
committerAndrew Dolgov <[email protected]>2011-12-26 12:02:52 +0400
commit8484ce22584b8714622833adcc7ebfe3ef9cf90e (patch)
tree057d7a64c3af60e2389d519ba19e476b5fbe6212
parent036cd3a4106cf2eee0be72f0695458dfb517976b (diff)
experimental CSRF protection
-rw-r--r--backend.php28
-rw-r--r--classes/article.php6
-rw-r--r--classes/feeds.php6
-rw-r--r--classes/handler.php4
-rw-r--r--classes/pref_feeds.php7
-rw-r--r--classes/pref_filters.php6
-rw-r--r--classes/pref_instances.php6
-rw-r--r--classes/pref_labels.php6
-rw-r--r--classes/pref_prefs.php6
-rw-r--r--classes/pref_users.php7
-rw-r--r--classes/rpc.php6
-rw-r--r--include/functions.php7
-rw-r--r--js/functions.js19
-rw-r--r--js/tt-rss.js1
14 files changed, 106 insertions, 9 deletions
diff --git a/backend.php b/backend.php
index 1805ce360..2e4da500f 100644
--- a/backend.php
+++ b/backend.php
@@ -1,5 +1,5 @@
<?php
- set_include_path(get_include_path() . PATH_SEPARATOR .
+ set_include_path(get_include_path() . PATH_SEPARATOR .
dirname(__FILE__) . "/include");
/* remove ill effects of magic quotes */
@@ -20,6 +20,11 @@
$op = $_REQUEST["op"];
@$method = $_REQUEST['subop'] ? $_REQUEST['subop'] : $_REQUEST["method"];
+ if (!$method)
+ $method = 'index';
+ else
+ $method = strtolower($method);
+
/* Public calls compatibility shim */
$public_calls = array("globalUpdateFeeds", "rss", "getUnread", "getProfiles", "share",
@@ -30,6 +35,11 @@
return;
}
+ $csrf_token = $_REQUEST['csrf_token'];
+
+ if (!$csrf_token)
+ error_log("[$op/$method] CSRF: [$csrf_token]\n", 3, "/tmp/csrf.log");
+
require_once "functions.php";
require_once "sessions.php";
require_once "sanity_check.php";
@@ -138,13 +148,17 @@
$handler = new $op($link, $_REQUEST);
if ($handler) {
- if ($handler->before($method)) {
- if ($method && method_exists($handler, $method)) {
- $handler->$method();
- } else if (method_exists($handler, 'index')) {
- $handler->index();
+ if (validate_csrf($csrf_token) || $handler->csrf_ignore($method)) {
+ if ($handler->before($method)) {
+ if ($method && method_exists($handler, $method)) {
+ $handler->$method();
+ }
+ $handler->after();
+ return;
}
- $handler->after();
+ } else {
+ header("Content-Type: text/plain");
+ print json_encode(array("error" => array("code" => 6)));
return;
}
}
diff --git a/classes/article.php b/classes/article.php
index 90ca129b9..30f0c7d10 100644
--- a/classes/article.php
+++ b/classes/article.php
@@ -1,6 +1,12 @@
<?php
class Article extends Protected_Handler {
+ function csrf_ignore($method) {
+ $csrf_ignored = array("redirect");
+
+ return array_search($method, $csrf_ignored) !== false;
+ }
+
function redirect() {
$id = db_escape_string($_REQUEST['id']);
diff --git a/classes/feeds.php b/classes/feeds.php
index 3626e9fbc..6b498ac00 100644
--- a/classes/feeds.php
+++ b/classes/feeds.php
@@ -1,6 +1,12 @@
<?php
class Feeds extends Protected_Handler {
+ function csrf_ignore($method) {
+ $csrf_ignored = array("index");
+
+ return array_search($method, $csrf_ignored) !== false;
+ }
+
private function feedlist_init_cat($cat_id, $hidden = false) {
$obj = array();
$cat_id = (int) $cat_id;
diff --git a/classes/handler.php b/classes/handler.php
index 53b52ea03..404b8306b 100644
--- a/classes/handler.php
+++ b/classes/handler.php
@@ -8,6 +8,10 @@ class Handler {
$this->args = $args;
}
+ function csrf_ignore($method) {
+ return true;
+ }
+
function before() {
return true;
}
diff --git a/classes/pref_feeds.php b/classes/pref_feeds.php
index 5df5eb939..b83abd789 100644
--- a/classes/pref_feeds.php
+++ b/classes/pref_feeds.php
@@ -1,5 +1,12 @@
<?php
class Pref_Feeds extends Protected_Handler {
+
+ function csrf_ignore($method) {
+ $csrf_ignored = array("index", "getfeedtree", "add", "editcats", "editfeed");
+
+ return array_search($method, $csrf_ignored) !== false;
+ }
+
function batch_edit_cbox($elem, $label = false) {
print "<input type=\"checkbox\" title=\"".__("Check to enable field")."\"
onchange=\"dijit.byId('feedEditDlg').toggleField(this, '$elem', '$label')\">";
diff --git a/classes/pref_filters.php b/classes/pref_filters.php
index d953a8d1d..4ab12410f 100644
--- a/classes/pref_filters.php
+++ b/classes/pref_filters.php
@@ -1,6 +1,12 @@
<?php
class Pref_Filters extends Protected_Handler {
+ function csrf_ignore($method) {
+ $csrf_ignored = array("index", "getfiltertree", "edit");
+
+ return array_search($method, $csrf_ignored) !== false;
+ }
+
function filter_test($filter_type, $reg_exp,
$action_id, $action_param, $filter_param, $inverse, $feed_id) {
diff --git a/classes/pref_instances.php b/classes/pref_instances.php
index 893d2b6bf..aae5bbafb 100644
--- a/classes/pref_instances.php
+++ b/classes/pref_instances.php
@@ -1,6 +1,12 @@
<?php
class Pref_Instances extends Protected_Handler {
+ function csrf_ignore($method) {
+ $csrf_ignored = array("index", "edit");
+
+ return array_search($method, $csrf_ignored) !== false;
+ }
+
function before() {
if (parent::before()) {
if ($_SESSION["access_level"] < 10) {
diff --git a/classes/pref_labels.php b/classes/pref_labels.php
index 0d60731f3..951ae45ed 100644
--- a/classes/pref_labels.php
+++ b/classes/pref_labels.php
@@ -1,6 +1,12 @@
<?php
class Pref_Labels extends Protected_Handler {
+ function csrf_ignore($method) {
+ $csrf_ignored = array("index", "getlabeltree", "edit");
+
+ return array_search($method, $csrf_ignored) !== false;
+ }
+
function edit() {
$label_id = db_escape_string($_REQUEST['id']);
diff --git a/classes/pref_prefs.php b/classes/pref_prefs.php
index 5a216d2b1..03e39caa5 100644
--- a/classes/pref_prefs.php
+++ b/classes/pref_prefs.php
@@ -1,6 +1,12 @@
<?php
class Pref_Prefs extends Protected_Handler {
+ function csrf_ignore($method) {
+ $csrf_ignored = array("index");
+
+ return array_search($method, $csrf_ignored) !== false;
+ }
+
function changepassword() {
$old_pw = $_POST["old_password"];
diff --git a/classes/pref_users.php b/classes/pref_users.php
index b9d162fd2..fe32ce14c 100644
--- a/classes/pref_users.php
+++ b/classes/pref_users.php
@@ -1,6 +1,5 @@
<?php
class Pref_Users extends Protected_Handler {
-
function before() {
if (parent::before()) {
if ($_SESSION["access_level"] < 10) {
@@ -12,6 +11,12 @@ class Pref_Users extends Protected_Handler {
return false;
}
+ function csrf_ignore($method) {
+ $csrf_ignored = array("index");
+
+ return array_search($method, $csrf_ignored) !== false;
+ }
+
function userdetails() {
header("Content-Type: text/xml");
diff --git a/classes/rpc.php b/classes/rpc.php
index 8145b0407..4cdaef935 100644
--- a/classes/rpc.php
+++ b/classes/rpc.php
@@ -1,6 +1,12 @@
<?php
class RPC extends Protected_Handler {
+ function csrf_ignore($method) {
+ $csrf_ignored = array("sanitycheck", "buttonplugin");
+
+ return array_search($method, $csrf_ignored) !== false;
+ }
+
function setprofile() {
$id = db_escape_string($_REQUEST["id"]);
diff --git a/include/functions.php b/include/functions.php
index e561d8e3d..ed28fd257 100644
--- a/include/functions.php
+++ b/include/functions.php
@@ -721,6 +721,7 @@
$_SESSION["uid"] = db_fetch_result($result, 0, "id");
$_SESSION["name"] = db_fetch_result($result, 0, "login");
$_SESSION["access_level"] = db_fetch_result($result, 0, "access_level");
+ $_SESSION["csrf_token"] = sha1(uniqid(rand(), true));
db_query($link, "UPDATE ttrss_users SET last_login = NOW() WHERE id = " .
$_SESSION["uid"]);
@@ -810,6 +811,10 @@
}
}
+ function validate_csrf($csrf_token) {
+ return $csrf_token == $_SESSION['csrf_token'];
+ }
+
function validate_session($link) {
if (SINGLE_USER_MODE) return true;
@@ -2064,6 +2069,8 @@
$params["collapsed_feedlist"] = (int) get_pref($link, "_COLLAPSED_FEEDLIST");
+ $params["csrf_token"] = $_SESSION["csrf_token"];
+
return $params;
}
diff --git a/js/functions.js b/js/functions.js
index 02134aafa..52201bd65 100644
--- a/js/functions.js
+++ b/js/functions.js
@@ -1,6 +1,25 @@
var notify_silent = false;
var loading_progress = 0;
var sanity_check_done = false;
+var init_params = {};
+
+Ajax.Base.prototype.initialize = Ajax.Base.prototype.initialize.wrap(
+ function (callOriginal, options) {
+
+ if (getInitParam("csrf_token") != undefined) {
+ Object.extend(options, options || { });
+
+ if (Object.isString(options.parameters))
+ options.parameters = options.parameters.toQueryParams();
+ else if (Object.isHash(options.parameters))
+ options.parameters = options.parameters.toObject();
+
+ options.parameters["csrf_token"] = getInitParam("csrf_token");
+ }
+
+ return callOriginal(options);
+ }
+);
/* add method to remove element from array */
diff --git a/js/tt-rss.js b/js/tt-rss.js
index 084a21863..4f82545f9 100644
--- a/js/tt-rss.js
+++ b/js/tt-rss.js
@@ -5,7 +5,6 @@ var _active_feed_id = 0;
var _active_feed_is_cat = false;
var hotkey_prefix = false;
var hotkey_prefix_pressed = false;
-var init_params = {};
var _force_scheduled_update = false;
var last_scheduled_update = false;