- backend: require CSRF token to be passed via POST

- do not leak CSRF token via GET request in feed debugger
- rework Article/redirect to use POST
This commit is contained in:
Andrew Dolgov 2020-09-15 16:12:53 +03:00
parent aeaafefa07
commit 8080c525fd
6 changed files with 45 additions and 41 deletions

View File

@ -20,7 +20,7 @@
return; return;
} }
@$csrf_token = $_REQUEST['csrf_token']; @$csrf_token = $_POST['csrf_token'];
require_once "autoload.php"; require_once "autoload.php";
require_once "sessions.php"; require_once "sessions.php";

View File

@ -751,7 +751,7 @@ class Feeds extends Handler_Protected {
$feed_id = (int)$_REQUEST["feed_id"]; $feed_id = (int)$_REQUEST["feed_id"];
@$do_update = $_REQUEST["action"] == "do_update"; @$do_update = $_REQUEST["action"] == "do_update";
$csrf_token = $_REQUEST["csrf_token"]; $csrf_token = $_POST["csrf_token"];
$sth = $this->pdo->prepare("SELECT id FROM ttrss_feeds WHERE id = ? AND owner_uid = ?"); $sth = $this->pdo->prepare("SELECT id FROM ttrss_feeds WHERE id = ? AND owner_uid = ?");
$sth->execute([$feed_id, $_SESSION['uid']]); $sth->execute([$feed_id, $_SESSION['uid']]);
@ -799,7 +799,7 @@ class Feeds extends Handler_Protected {
<div class="container"> <div class="container">
<h1>Feed Debugger: <?php echo "$feed_id: " . $this->getFeedTitle($feed_id) ?></h1> <h1>Feed Debugger: <?php echo "$feed_id: " . $this->getFeedTitle($feed_id) ?></h1>
<div class="content"> <div class="content">
<form method="GET" action=""> <form method="post" action="">
<input type="hidden" name="op" value="feeds"> <input type="hidden" name="op" value="feeds">
<input type="hidden" name="method" value="update_debugger"> <input type="hidden" name="method" value="update_debugger">
<input type="hidden" name="xdebug" value="1"> <input type="hidden" name="xdebug" value="1">

View File

@ -291,7 +291,7 @@ class Handler_Public extends Handler {
$uuid = clean($_REQUEST["key"]); $uuid = clean($_REQUEST["key"]);
if ($uuid) { if ($uuid) {
$sth = $this->pdo->prepare("SELECT ref_id, owner_uid $sth = $this->pdo->prepare("SELECT ref_id, owner_uid
FROM ttrss_user_entries WHERE uuid = ?"); FROM ttrss_user_entries WHERE uuid = ?");
$sth->execute([$uuid]); $sth->execute([$uuid]);
@ -366,7 +366,7 @@ class Handler_Public extends Handler {
} }
body.css_loading * { body.css_loading * {
display : none; display : none;
} }
</style> </style>
<link rel='shortcut icon' type='image/png' href='images/favicon.png'> <link rel='shortcut icon' type='image/png' href='images/favicon.png'>
<link rel='icon' type='image/png' sizes='72x72' href='images/favicon-72px.png'>"; <link rel='icon' type='image/png' sizes='72x72' href='images/favicon-72px.png'>";
@ -728,7 +728,7 @@ class Handler_Public extends Handler {
if ($_SESSION["uid"]) { if ($_SESSION["uid"]) {
$feed_url = trim(clean($_REQUEST["feed_url"])); $feed_url = trim(clean($_REQUEST["feed_url"]));
$csrf_token = clean($_REQUEST["csrf_token"]); $csrf_token = clean($_POST["csrf_token"]);
header('Content-Type: text/html; charset=utf-8'); header('Content-Type: text/html; charset=utf-8');
?> ?>

View File

@ -126,7 +126,33 @@ const App = {
return callOriginal(options); return callOriginal(options);
} }
); );
}, },
postOpenWindow: function(target, params) {
const w = window.open("");
if (w) {
w.opener = null;
const form = document.createElement("form");
form.setAttribute("method", "post");
form.setAttribute("action", App.getInitParam("self_url_prefix") + "/" + target);
for (const [k,v] of Object.entries(params)) {
const field = document.createElement("input");
field.setAttribute("name", k);
field.setAttribute("value", v);
field.setAttribute("type", "hidden");
form.appendChild(field);
}
w.document.body.appendChild(form);
form.submit();
}
},
urlParam: function(param) { urlParam: function(param) {
return String(window.location.href).parseQuery()[param]; return String(window.location.href).parseQuery()[param];
}, },
@ -986,8 +1012,11 @@ const App = {
}; };
this.hotkey_actions["feed_debug_update"] = () => { this.hotkey_actions["feed_debug_update"] = () => {
if (!Feeds.activeIsCat() && parseInt(Feeds.getActive()) > 0) { if (!Feeds.activeIsCat() && parseInt(Feeds.getActive()) > 0) {
window.open("backend.php?op=feeds&method=update_debugger&feed_id=" + Feeds.getActive() + //window.open("backend.php?op=feeds&method=update_debugger&feed_id=" + Feeds.getActive());
"&csrf_token=" + this.getInitParam("csrf_token"));
/* global __csrf_token */
App.postOpenWindow("backend.php", {op: "feeds", method: "update_debugger", feed_id: Feeds.getActive(), csrf_token: __csrf_token});
} else { } else {
alert("You can't debug this kind of feed."); alert("You can't debug this kind of feed.");
} }

View File

@ -131,37 +131,11 @@ const Article = {
}); });
}, },
openInNewWindow: function (id) { openInNewWindow: function (id) {
/* global __csrf_token */
App.postOpenWindow("backend.php",
{ "op": "article", "method": "redirect", "id": id, "csrf_token": __csrf_token });
const w = window.open(""); Headlines.toggleUnread(id, 0);
if (w) {
w.opener = null;
const form = document.createElement("form");
form.setAttribute("method", "post");
form.setAttribute("action", App.getInitParam("self_url_prefix") + "/backend.php");
/* global __csrf_token */
const params = { "op": "article", "method": "redirect", "id": id, "csrf_token": __csrf_token };
for (const [k,v] of Object.entries(params)) {
const field = document.createElement("input");
field.setAttribute("name", k);
field.setAttribute("value", v);
field.setAttribute("type", "hidden");
form.appendChild(field);
}
w.document.body.appendChild(form);
form.submit();
Headlines.toggleUnread(id, 0);
}
}, },
render: function (article) { render: function (article) {
App.cleanupMemory("content-insert"); App.cleanupMemory("content-insert");

View File

@ -101,8 +101,9 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dojo/_base/array", "dojo/co
menu.addChild(new dijit.MenuItem({ menu.addChild(new dijit.MenuItem({
label: __("Debug feed"), label: __("Debug feed"),
onClick: function() { onClick: function() {
window.open("backend.php?op=feeds&method=update_debugger&feed_id=" + this.getParent().row_id + /* global __csrf_token */
"&csrf_token=" + App.getInitParam("csrf_token")); App.postOpenWindow("backend.php", {op: "feeds", method: "update_debugger",
feed_id: this.getParent().row_id, csrf_token: __csrf_token});
}})); }}));
} }