diff options
author | Andrew Dolgov <[email protected]> | 2011-12-26 12:02:52 +0400 |
---|---|---|
committer | Andrew Dolgov <[email protected]> | 2011-12-26 12:02:52 +0400 |
commit | 8484ce22584b8714622833adcc7ebfe3ef9cf90e (patch) | |
tree | 057d7a64c3af60e2389d519ba19e476b5fbe6212 | |
parent | 036cd3a4106cf2eee0be72f0695458dfb517976b (diff) |
experimental CSRF protection
-rw-r--r-- | backend.php | 28 | ||||
-rw-r--r-- | classes/article.php | 6 | ||||
-rw-r--r-- | classes/feeds.php | 6 | ||||
-rw-r--r-- | classes/handler.php | 4 | ||||
-rw-r--r-- | classes/pref_feeds.php | 7 | ||||
-rw-r--r-- | classes/pref_filters.php | 6 | ||||
-rw-r--r-- | classes/pref_instances.php | 6 | ||||
-rw-r--r-- | classes/pref_labels.php | 6 | ||||
-rw-r--r-- | classes/pref_prefs.php | 6 | ||||
-rw-r--r-- | classes/pref_users.php | 7 | ||||
-rw-r--r-- | classes/rpc.php | 6 | ||||
-rw-r--r-- | include/functions.php | 7 | ||||
-rw-r--r-- | js/functions.js | 19 | ||||
-rw-r--r-- | js/tt-rss.js | 1 |
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; |