fix OTP QR code not displayed because of CSRF token passed as a query

parameter
use type-strict comparison when validating CSRF token on the backend
This commit is contained in:
Andrew Dolgov 2020-09-17 08:43:39 +03:00
parent 6a4b6cf603
commit 1f79d614c4
3 changed files with 27 additions and 17 deletions

View File

@ -283,9 +283,12 @@ class Handler_Public extends Handler {
} }
function logout() { function logout() {
if ($_POST["csrf_token"] == $_SESSION["csrf_token"]) { if (validate_csrf($_POST["csrf_token"])) {
logout_user(); logout_user();
header("Location: index.php"); header("Location: index.php");
} else {
header("Content-Type: text/json");
print error_json(6);
} }
} }
@ -777,7 +780,7 @@ class Handler_Public extends Handler {
<div class='content'> <div class='content'>
<?php <?php
if (!$feed_url || $csrf_token != $_SESSION["csrf_token"]) { if (!$feed_url || !validate_csrf($csrf_token)) {
?> ?>
<form method="post"> <form method="post">
<input type="hidden" name="op" value="subscribe"> <input type="hidden" name="op" value="subscribe">

View File

@ -8,7 +8,7 @@ class Pref_Prefs extends Handler_Protected {
private $profile_blacklist = []; private $profile_blacklist = [];
function csrf_ignore($method) { function csrf_ignore($method) {
$csrf_ignored = array("index", "updateself", "customizecss", "editprefprofiles"); $csrf_ignored = array("index", "updateself", "customizecss", "editprefprofiles", "otpqrcode");
return array_search($method, $csrf_ignored) !== false; return array_search($method, $csrf_ignored) !== false;
} }
@ -483,8 +483,8 @@ class Pref_Prefs extends Handler_Protected {
if (function_exists("imagecreatefromstring")) { if (function_exists("imagecreatefromstring")) {
print "<h3>" . __("Scan the following code by the Authenticator application or copy the key manually") . "</h3>"; print "<h3>" . __("Scan the following code by the Authenticator application or copy the key manually") . "</h3>";
$csrf_token = $_SESSION["csrf_token"]; $csrf_token_hash = sha1($_SESSION["csrf_token"]);
print "<img alt='otp qr-code' src='backend.php?op=pref-prefs&method=otpqrcode&csrf_token=$csrf_token'>"; print "<img alt='otp qr-code' src='backend.php?op=pref-prefs&method=otpqrcode&csrf_token_hash=$csrf_token_hash'>";
} else { } else {
print_error("PHP GD functions are required to generate QR codes."); print_error("PHP GD functions are required to generate QR codes.");
print "<h3>" . __("Use the following OTP key with a compatible Authenticator application") . "</h3>"; print "<h3>" . __("Use the following OTP key with a compatible Authenticator application") . "</h3>";
@ -1010,21 +1010,28 @@ class Pref_Prefs extends Handler_Protected {
} }
function otpqrcode() { function otpqrcode() {
require_once "lib/phpqrcode/phpqrcode.php"; $csrf_token_hash = clean($_REQUEST["csrf_token_hash"]);
$sth = $this->pdo->prepare("SELECT login if (sha1($_SESSION["csrf_token"] === $csrf_token_hash)) {
FROM ttrss_users require_once "lib/phpqrcode/phpqrcode.php";
WHERE id = ?");
$sth->execute([$_SESSION['uid']]);
if ($row = $sth->fetch()) { $sth = $this->pdo->prepare("SELECT login
$secret = $this->otpsecret(); FROM ttrss_users
$login = $row['login']; WHERE id = ?");
$sth->execute([$_SESSION['uid']]);
if ($secret) { if ($row = $sth->fetch()) {
QRcode::png("otpauth://totp/".urlencode($login). $secret = $this->otpsecret();
"?secret=$secret&issuer=".urlencode("Tiny Tiny RSS")); $login = $row['login'];
if ($secret) {
QRcode::png("otpauth://totp/".urlencode($login).
"?secret=$secret&issuer=".urlencode("Tiny Tiny RSS"));
}
} }
} else {
header("Content-Type: text/json");
print error_json(6);
} }
} }

View File

@ -680,7 +680,7 @@
} }
function validate_csrf($csrf_token) { function validate_csrf($csrf_token) {
return $csrf_token == $_SESSION['csrf_token']; return $csrf_token === $_SESSION['csrf_token'];
} }
function load_user_plugins($owner_uid, $pluginhost = false) { function load_user_plugins($owner_uid, $pluginhost = false) {