experimental CSRF protection
This commit is contained in:
parent
036cd3a410
commit
8484ce2258
26
backend.php
26
backend.php
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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']);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -8,6 +8,10 @@ class Handler {
|
|||
$this->args = $args;
|
||||
}
|
||||
|
||||
function csrf_ignore($method) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function before() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -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')\">";
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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']);
|
||||
|
||||
|
|
|
@ -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"];
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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"]);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue