experimental CSRF protection
This commit is contained in:
parent
036cd3a410
commit
8484ce2258
18
backend.php
18
backend.php
|
@ -20,6 +20,11 @@
|
||||||
$op = $_REQUEST["op"];
|
$op = $_REQUEST["op"];
|
||||||
@$method = $_REQUEST['subop'] ? $_REQUEST['subop'] : $_REQUEST["method"];
|
@$method = $_REQUEST['subop'] ? $_REQUEST['subop'] : $_REQUEST["method"];
|
||||||
|
|
||||||
|
if (!$method)
|
||||||
|
$method = 'index';
|
||||||
|
else
|
||||||
|
$method = strtolower($method);
|
||||||
|
|
||||||
/* Public calls compatibility shim */
|
/* Public calls compatibility shim */
|
||||||
|
|
||||||
$public_calls = array("globalUpdateFeeds", "rss", "getUnread", "getProfiles", "share",
|
$public_calls = array("globalUpdateFeeds", "rss", "getUnread", "getProfiles", "share",
|
||||||
|
@ -30,6 +35,11 @@
|
||||||
return;
|
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 "functions.php";
|
||||||
require_once "sessions.php";
|
require_once "sessions.php";
|
||||||
require_once "sanity_check.php";
|
require_once "sanity_check.php";
|
||||||
|
@ -138,15 +148,19 @@
|
||||||
$handler = new $op($link, $_REQUEST);
|
$handler = new $op($link, $_REQUEST);
|
||||||
|
|
||||||
if ($handler) {
|
if ($handler) {
|
||||||
|
if (validate_csrf($csrf_token) || $handler->csrf_ignore($method)) {
|
||||||
if ($handler->before($method)) {
|
if ($handler->before($method)) {
|
||||||
if ($method && method_exists($handler, $method)) {
|
if ($method && method_exists($handler, $method)) {
|
||||||
$handler->$method();
|
$handler->$method();
|
||||||
} else if (method_exists($handler, 'index')) {
|
|
||||||
$handler->index();
|
|
||||||
}
|
}
|
||||||
$handler->after();
|
$handler->after();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
header("Content-Type: text/plain");
|
||||||
|
print json_encode(array("error" => array("code" => 6)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
<?php
|
<?php
|
||||||
class Article extends Protected_Handler {
|
class Article extends Protected_Handler {
|
||||||
|
|
||||||
|
function csrf_ignore($method) {
|
||||||
|
$csrf_ignored = array("redirect");
|
||||||
|
|
||||||
|
return array_search($method, $csrf_ignored) !== false;
|
||||||
|
}
|
||||||
|
|
||||||
function redirect() {
|
function redirect() {
|
||||||
$id = db_escape_string($_REQUEST['id']);
|
$id = db_escape_string($_REQUEST['id']);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
<?php
|
<?php
|
||||||
class Feeds extends Protected_Handler {
|
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) {
|
private function feedlist_init_cat($cat_id, $hidden = false) {
|
||||||
$obj = array();
|
$obj = array();
|
||||||
$cat_id = (int) $cat_id;
|
$cat_id = (int) $cat_id;
|
||||||
|
|
|
@ -8,6 +8,10 @@ class Handler {
|
||||||
$this->args = $args;
|
$this->args = $args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function csrf_ignore($method) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
function before() {
|
function before() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
<?php
|
<?php
|
||||||
class Pref_Feeds extends Protected_Handler {
|
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) {
|
function batch_edit_cbox($elem, $label = false) {
|
||||||
print "<input type=\"checkbox\" title=\"".__("Check to enable field")."\"
|
print "<input type=\"checkbox\" title=\"".__("Check to enable field")."\"
|
||||||
onchange=\"dijit.byId('feedEditDlg').toggleField(this, '$elem', '$label')\">";
|
onchange=\"dijit.byId('feedEditDlg').toggleField(this, '$elem', '$label')\">";
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
<?php
|
<?php
|
||||||
class Pref_Filters extends Protected_Handler {
|
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,
|
function filter_test($filter_type, $reg_exp,
|
||||||
$action_id, $action_param, $filter_param, $inverse, $feed_id) {
|
$action_id, $action_param, $filter_param, $inverse, $feed_id) {
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
<?php
|
<?php
|
||||||
class Pref_Instances extends Protected_Handler {
|
class Pref_Instances extends Protected_Handler {
|
||||||
|
|
||||||
|
function csrf_ignore($method) {
|
||||||
|
$csrf_ignored = array("index", "edit");
|
||||||
|
|
||||||
|
return array_search($method, $csrf_ignored) !== false;
|
||||||
|
}
|
||||||
|
|
||||||
function before() {
|
function before() {
|
||||||
if (parent::before()) {
|
if (parent::before()) {
|
||||||
if ($_SESSION["access_level"] < 10) {
|
if ($_SESSION["access_level"] < 10) {
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
<?php
|
<?php
|
||||||
class Pref_Labels extends Protected_Handler {
|
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() {
|
function edit() {
|
||||||
$label_id = db_escape_string($_REQUEST['id']);
|
$label_id = db_escape_string($_REQUEST['id']);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
<?php
|
<?php
|
||||||
class Pref_Prefs extends Protected_Handler {
|
class Pref_Prefs extends Protected_Handler {
|
||||||
|
|
||||||
|
function csrf_ignore($method) {
|
||||||
|
$csrf_ignored = array("index");
|
||||||
|
|
||||||
|
return array_search($method, $csrf_ignored) !== false;
|
||||||
|
}
|
||||||
|
|
||||||
function changepassword() {
|
function changepassword() {
|
||||||
|
|
||||||
$old_pw = $_POST["old_password"];
|
$old_pw = $_POST["old_password"];
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
class Pref_Users extends Protected_Handler {
|
class Pref_Users extends Protected_Handler {
|
||||||
|
|
||||||
function before() {
|
function before() {
|
||||||
if (parent::before()) {
|
if (parent::before()) {
|
||||||
if ($_SESSION["access_level"] < 10) {
|
if ($_SESSION["access_level"] < 10) {
|
||||||
|
@ -12,6 +11,12 @@ class Pref_Users extends Protected_Handler {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function csrf_ignore($method) {
|
||||||
|
$csrf_ignored = array("index");
|
||||||
|
|
||||||
|
return array_search($method, $csrf_ignored) !== false;
|
||||||
|
}
|
||||||
|
|
||||||
function userdetails() {
|
function userdetails() {
|
||||||
|
|
||||||
header("Content-Type: text/xml");
|
header("Content-Type: text/xml");
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
<?php
|
<?php
|
||||||
class RPC extends Protected_Handler {
|
class RPC extends Protected_Handler {
|
||||||
|
|
||||||
|
function csrf_ignore($method) {
|
||||||
|
$csrf_ignored = array("sanitycheck", "buttonplugin");
|
||||||
|
|
||||||
|
return array_search($method, $csrf_ignored) !== false;
|
||||||
|
}
|
||||||
|
|
||||||
function setprofile() {
|
function setprofile() {
|
||||||
$id = db_escape_string($_REQUEST["id"]);
|
$id = db_escape_string($_REQUEST["id"]);
|
||||||
|
|
||||||
|
|
|
@ -721,6 +721,7 @@
|
||||||
$_SESSION["uid"] = db_fetch_result($result, 0, "id");
|
$_SESSION["uid"] = db_fetch_result($result, 0, "id");
|
||||||
$_SESSION["name"] = db_fetch_result($result, 0, "login");
|
$_SESSION["name"] = db_fetch_result($result, 0, "login");
|
||||||
$_SESSION["access_level"] = db_fetch_result($result, 0, "access_level");
|
$_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 = " .
|
db_query($link, "UPDATE ttrss_users SET last_login = NOW() WHERE id = " .
|
||||||
$_SESSION["uid"]);
|
$_SESSION["uid"]);
|
||||||
|
@ -810,6 +811,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function validate_csrf($csrf_token) {
|
||||||
|
return $csrf_token == $_SESSION['csrf_token'];
|
||||||
|
}
|
||||||
|
|
||||||
function validate_session($link) {
|
function validate_session($link) {
|
||||||
if (SINGLE_USER_MODE) return true;
|
if (SINGLE_USER_MODE) return true;
|
||||||
|
|
||||||
|
@ -2064,6 +2069,8 @@
|
||||||
|
|
||||||
$params["collapsed_feedlist"] = (int) get_pref($link, "_COLLAPSED_FEEDLIST");
|
$params["collapsed_feedlist"] = (int) get_pref($link, "_COLLAPSED_FEEDLIST");
|
||||||
|
|
||||||
|
$params["csrf_token"] = $_SESSION["csrf_token"];
|
||||||
|
|
||||||
return $params;
|
return $params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,25 @@
|
||||||
var notify_silent = false;
|
var notify_silent = false;
|
||||||
var loading_progress = 0;
|
var loading_progress = 0;
|
||||||
var sanity_check_done = false;
|
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 */
|
/* add method to remove element from array */
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ var _active_feed_id = 0;
|
||||||
var _active_feed_is_cat = false;
|
var _active_feed_is_cat = false;
|
||||||
var hotkey_prefix = false;
|
var hotkey_prefix = false;
|
||||||
var hotkey_prefix_pressed = false;
|
var hotkey_prefix_pressed = false;
|
||||||
var init_params = {};
|
|
||||||
var _force_scheduled_update = false;
|
var _force_scheduled_update = false;
|
||||||
var last_scheduled_update = false;
|
var last_scheduled_update = false;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue