From 1f79d614c4d24fdc0432fd6d080f29ca99b41fbf Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Thu, 17 Sep 2020 08:43:39 +0300 Subject: [PATCH] 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 --- classes/handler/public.php | 7 +++++-- classes/pref/prefs.php | 35 +++++++++++++++++++++-------------- include/functions.php | 2 +- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/classes/handler/public.php b/classes/handler/public.php index 18be5c640..595473789 100755 --- a/classes/handler/public.php +++ b/classes/handler/public.php @@ -283,9 +283,12 @@ class Handler_Public extends Handler { } function logout() { - if ($_POST["csrf_token"] == $_SESSION["csrf_token"]) { + if (validate_csrf($_POST["csrf_token"])) { logout_user(); header("Location: index.php"); + } else { + header("Content-Type: text/json"); + print error_json(6); } } @@ -777,7 +780,7 @@ class Handler_Public extends Handler {
diff --git a/classes/pref/prefs.php b/classes/pref/prefs.php index b3341623c..3b129c7e5 100644 --- a/classes/pref/prefs.php +++ b/classes/pref/prefs.php @@ -8,7 +8,7 @@ class Pref_Prefs extends Handler_Protected { private $profile_blacklist = []; 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; } @@ -483,8 +483,8 @@ class Pref_Prefs extends Handler_Protected { if (function_exists("imagecreatefromstring")) { print "

" . __("Scan the following code by the Authenticator application or copy the key manually") . "

"; - $csrf_token = $_SESSION["csrf_token"]; - print "otp qr-code"; + $csrf_token_hash = sha1($_SESSION["csrf_token"]); + print "otp qr-code"; } else { print_error("PHP GD functions are required to generate QR codes."); print "

" . __("Use the following OTP key with a compatible Authenticator application") . "

"; @@ -1010,21 +1010,28 @@ class Pref_Prefs extends Handler_Protected { } function otpqrcode() { - require_once "lib/phpqrcode/phpqrcode.php"; + $csrf_token_hash = clean($_REQUEST["csrf_token_hash"]); - $sth = $this->pdo->prepare("SELECT login - FROM ttrss_users - WHERE id = ?"); - $sth->execute([$_SESSION['uid']]); + if (sha1($_SESSION["csrf_token"] === $csrf_token_hash)) { + require_once "lib/phpqrcode/phpqrcode.php"; - if ($row = $sth->fetch()) { - $secret = $this->otpsecret(); - $login = $row['login']; + $sth = $this->pdo->prepare("SELECT login + FROM ttrss_users + WHERE id = ?"); + $sth->execute([$_SESSION['uid']]); - if ($secret) { - QRcode::png("otpauth://totp/".urlencode($login). - "?secret=$secret&issuer=".urlencode("Tiny Tiny RSS")); + if ($row = $sth->fetch()) { + $secret = $this->otpsecret(); + $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); } } diff --git a/include/functions.php b/include/functions.php index dfaf1895d..9989d7ecf 100644 --- a/include/functions.php +++ b/include/functions.php @@ -680,7 +680,7 @@ } 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) {