From c1307416787d0e7762c96875e351819e5bc562ee Mon Sep 17 00:00:00 2001 From: ghost Date: Mon, 3 Jan 2022 20:49:21 +0200 Subject: [PATCH] DHT/twisterd interaction security fix --- src/application/controller/api/follow/add.php | 2 +- .../controller/api/follow/total.php | 2 +- src/application/controller/api/post/add.php | 3 +- src/application/controller/api/post/get.php | 30 ++++++--- .../controller/api/user/avatar.php | 12 ++-- .../controller/api/user/profile.php | 36 +++++------ src/application/controller/register.php | 8 --- .../controller/settings/profile.php | 61 ++++++++++--------- src/system/helper/filter.php | 19 +++++- tool/crawler/blockchain.php | 5 ++ 10 files changed, 103 insertions(+), 75 deletions(-) diff --git a/src/application/controller/api/follow/add.php b/src/application/controller/api/follow/add.php index baebf34..fd990d6 100644 --- a/src/application/controller/api/follow/add.php +++ b/src/application/controller/api/follow/add.php @@ -7,7 +7,7 @@ $response = [ if (isset($_SESSION['userName']) && isset($_POST['userName'])) { - $result = $_twister->follow($_SESSION['userName'], [$_POST['userName']]); + $result = $_twister->follow($_SESSION['userName'], [Filter::userName($_POST['userName'])]); $response = [ 'success' => true, diff --git a/src/application/controller/api/follow/total.php b/src/application/controller/api/follow/total.php index bc2322f..3b13cc9 100644 --- a/src/application/controller/api/follow/total.php +++ b/src/application/controller/api/follow/total.php @@ -8,7 +8,7 @@ $response = [ if (isset($_SESSION['userName'])) { - $userName = isset($_POST['userName']) ? $_POST['userName'] : $_SESSION['userName']; + $userName = isset($_POST['userName']) ? Filter::userName($_POST['userName']) : $_SESSION['userName']; $followingUsersTotal = 0; diff --git a/src/application/controller/api/post/add.php b/src/application/controller/api/post/add.php index 6224197..0a9609a 100644 --- a/src/application/controller/api/post/add.php +++ b/src/application/controller/api/post/add.php @@ -21,7 +21,8 @@ if (isset($_SESSION['userName'])) { 'message' => _('Could not receive user post') ]; - } else if (isset($userPosts[0]['userpost']['k']) && $result = $_twister->newPostMessage($_SESSION['userName'], $userPosts[0]['userpost']['k'] + 1, $_POST['message'])) { + } else if (isset($userPosts[0]['userpost']['k']) && + $result = $_twister->newPostMessage($_SESSION['userName'], Filter::int($userPosts[0]['userpost']['k']) + 1, $_POST['message'])) { $response = [ 'success' => true, diff --git a/src/application/controller/api/post/get.php b/src/application/controller/api/post/get.php index 0e7020e..d7a491e 100644 --- a/src/application/controller/api/post/get.php +++ b/src/application/controller/api/post/get.php @@ -8,7 +8,19 @@ $response = [ if (isset($_SESSION['userName'])) { - $userNames = isset($_GET['userName']) && $_GET['userName'] ? [Filter::userName($_GET['userName'])] : $_twister->getFollowing($_SESSION['userName']); + $userNames = []; + + if (isset($_GET['userName']) && !empty($_GET['userName'])) { + + $userNames[] = Filter::userName($_GET['userName']); + + } else { + + foreach ((array) $_twister->getFollowing($_SESSION['userName']) as $followingUserName) { + + $userNames[] = Filter::userName($followingUserName); + } + } if ($result = $_twister->getPosts($userNames, APPLICATION_MAX_POST_FEED)) { @@ -16,14 +28,14 @@ if (isset($_SESSION['userName'])) { foreach ($result as $post) { // Split message parts - $messages = [$post['userpost']['msg']]; + $messages = [Filter::string($post['userpost']['msg'])]; for ($i = 0; $i <= APPLICATION_MAX_POST_SPLIT; $i++) { $n = sprintf('msg%s', $i); if (isset($post['userpost'][$n])) { - $messages[] = $post['userpost'][$n]; + $messages[] = Filter::string($post['userpost'][$n]); } } @@ -32,29 +44,29 @@ if (isset($_SESSION['userName'])) { if (isset($post['userpost']['rt'])) { // Split reTwists parts - $reTwists = [$post['userpost']['rt']['msg']]; + $reTwists = [Filter::string($post['userpost']['rt']['msg'])]; for ($i = 0; $i <= APPLICATION_MAX_POST_SPLIT; $i++) { $n = sprintf('msg%s', $i); if (isset($post['userpost']['rt'][$n])) { - $reTwists[] = $post['userpost']['rt'][$n]; + $reTwists[] = Filter::string($post['userpost']['rt'][$n]); } } $reTwist = [ 'message' => Format::post(implode('', $reTwists)), - 'time' => Format::time($post['userpost']['rt']['time']), - 'userName' => $post['userpost']['rt']['n'], + 'time' => Format::time(Filter::int($post['userpost']['rt']['time'])), + 'userName' => Filter::userName($post['userpost']['rt']['n']), 'reTwist' => $reTwist, ]; } $posts[] = [ 'message' => Format::post(implode('', $messages)), - 'time' => Format::time($post['userpost']['time']), - 'userName' => $post['userpost']['n'], + 'time' => Format::time(Filter::int($post['userpost']['time'])), + 'userName' => Filter::userName($post['userpost']['n']), 'reTwist' => $reTwist, ]; } diff --git a/src/application/controller/api/user/avatar.php b/src/application/controller/api/user/avatar.php index 259b2d0..04ef82f 100644 --- a/src/application/controller/api/user/avatar.php +++ b/src/application/controller/api/user/avatar.php @@ -27,14 +27,14 @@ if (isset($_SESSION['userName'])) { foreach ($avatarVersions as $avatarVersion) { if (!$_modelAvatar->versionExists($userId, - $avatarVersion['p']['height'], - $avatarVersion['p']['seq'])) { + Filter::int($avatarVersion['p']['height']), + Filter::int($avatarVersion['p']['seq']))) { $_modelAvatar->add( $userId, - $avatarVersion['p']['height'], - $avatarVersion['p']['seq'], - $avatarVersion['p']['time'], - $avatarVersion['p']['v']); + Filter::int($avatarVersion['p']['height']), + Filter::int($avatarVersion['p']['seq']), + Filter::int($avatarVersion['p']['time']), + Filter::string($avatarVersion['p']['v'])); } } } diff --git a/src/application/controller/api/user/profile.php b/src/application/controller/api/user/profile.php index 8dff279..483b1e9 100644 --- a/src/application/controller/api/user/profile.php +++ b/src/application/controller/api/user/profile.php @@ -27,22 +27,22 @@ if (isset($_SESSION['userName'])) { foreach ($userProfileVersions as $userProfileVersion) { if (!$_modelProfile->versionExists($userId, - $userProfileVersion['p']['height'], - $userProfileVersion['p']['seq'])) { + Filter::int($userProfileVersion['p']['height']), + Filter::int($userProfileVersion['p']['seq']))) { $profile = $userProfileVersion['p']['v']; $_modelProfile->add($userId, - $userProfileVersion['p']['height'], - $userProfileVersion['p']['seq'], - $userProfileVersion['p']['time'], - - isset($profile['fullname']) ? $profile['fullname'] : '', - isset($profile['bio']) ? $profile['bio'] : '', - isset($profile['location']) ? $profile['location'] : '', - isset($profile['url']) ? $profile['url'] : '', - isset($profile['bitmessage']) ? $profile['bitmessage'] : '', - isset($profile['tox']) ? $profile['tox'] : ''); + Filter::int($userProfileVersion['p']['height']), + Filter::int($userProfileVersion['p']['seq']), + Filter::int($userProfileVersion['p']['time']), + + isset($profile['fullname']) ? Filter::string($profile['fullname']) : '', + isset($profile['bio']) ? Filter::string($profile['bio']) : '', + isset($profile['location']) ? Filter::string($profile['location']) : '', + isset($profile['url']) ? Filter::string($profile['url']) : '', + isset($profile['bitmessage']) ? Filter::string($profile['bitmessage']) : '', + isset($profile['tox']) ? Filter::string($profile['tox']) : ''); } } } @@ -52,12 +52,12 @@ if (isset($_SESSION['userName'])) { $profile = [ 'userName' => $userName, - 'fullName' => $profileInfo['fullName'], - 'location' => $profileInfo['location'], - 'url' => $profileInfo['url'], - 'bitMessage' => $profileInfo['bitMessage'], - 'tox' => $profileInfo['tox'], - 'bio' => nl2br($profileInfo['bio']), + 'fullName' => Filter::string($profileInfo['fullName']), + 'location' => Filter::string($profileInfo['location']), + 'url' => Filter::string($profileInfo['url']), + 'bitMessage' => Filter::string($profileInfo['bitMessage']), + 'tox' => Filter::string($profileInfo['tox']), + 'bio' => nl2br(Filter::string($profileInfo['bio'])), ]; $response = [ diff --git a/src/application/controller/register.php b/src/application/controller/register.php index dbf75a8..887e3c3 100644 --- a/src/application/controller/register.php +++ b/src/application/controller/register.php @@ -83,15 +83,7 @@ if (isset($_POST) && $_POST) { require(PROJECT_DIR . '/application/view/welcome.phtml'); exit; - - } else { - - trigger_error($_twister->getError()); } - - } else { - - trigger_error($_twister->getError()); } } } diff --git a/src/application/controller/settings/profile.php b/src/application/controller/settings/profile.php index 85eefbb..e8e1da9 100644 --- a/src/application/controller/settings/profile.php +++ b/src/application/controller/settings/profile.php @@ -41,12 +41,12 @@ $errorBio = false; if (isset($_POST) && !empty($_POST)) { // Prepare request - $fullName = isset($_POST['fullName']) ? $_POST['fullName'] : ''; - $location = isset($_POST['location']) ? $_POST['location'] : ''; - $url = isset($_POST['url']) ? $_POST['url'] : ''; - $bitMessage = isset($_POST['bitMessage']) ? $_POST['bitMessage'] : ''; - $tox = isset($_POST['tox']) ? $_POST['tox'] : ''; - $bio = isset($_POST['bio']) ? $_POST['bio'] : ''; + $fullName = isset($_POST['fullName']) ? Filter::string($_POST['fullName']) : ''; + $location = isset($_POST['location']) ? Filter::string($_POST['location']) : ''; + $url = isset($_POST['url']) ? Filter::string($_POST['url']) : ''; + $bitMessage = isset($_POST['bitMessage']) ? Filter::string($_POST['bitMessage']) : ''; + $tox = isset($_POST['tox']) ? Filter::string($_POST['tox']) : ''; + $bio = isset($_POST['bio']) ? Filter::string($_POST['bio']) : ''; // Get current block number $blockId = $_modelBlock->getThisBlock(); @@ -94,7 +94,7 @@ if (isset($_POST) && !empty($_POST)) { } // Update avatar cache - $_memcache->set('api.user.avatar.' . $_SESSION['userName'], $avatar, MEMCACHE_COMPRESS, MEMCACHE_DHT_AVATAR_TIMEOUT); + $_memcache->replace('api.user.avatar.' . $_SESSION['userName'], $avatar, MEMCACHE_COMPRESS, MEMCACHE_DHT_AVATAR_TIMEOUT); } // Get profile revision @@ -164,14 +164,14 @@ if ($userAvatar = $_memcache->get('api.user.avatar.' . $_SESSION['userName'])) { foreach ($avatarVersions as $avatarVersion) { if (!$_modelAvatar->versionExists($_SESSION['userId'], - $avatarVersion['p']['height'], - $avatarVersion['p']['seq'])) { + Filter::int($avatarVersion['p']['height']), + Filter::int($avatarVersion['p']['seq']))) { $_modelAvatar->add( $_SESSION['userId'], - $avatarVersion['p']['height'], - $avatarVersion['p']['seq'], - $avatarVersion['p']['time'], - $avatarVersion['p']['v']); + Filter::int($avatarVersion['p']['height']), + Filter::int($avatarVersion['p']['seq']), + Filter::int($avatarVersion['p']['time']), + Filter::string($avatarVersion['p']['v'])); } } @@ -200,7 +200,7 @@ if ($userAvatar = $_memcache->get('api.user.avatar.' . $_SESSION['userName'])) { $avatar = sprintf('data:image/jpeg;base64,%s', base64_encode(file_get_contents($filePath))); } -// Get profile details +// Get profile details from cache if ($profile = $_memcache->get('api.user.profile.' . $_SESSION['userName'])) { $fullName = $profile['fullName']; @@ -210,28 +210,32 @@ if ($profile = $_memcache->get('api.user.profile.' . $_SESSION['userName'])) { $tox = $profile['tox']; $bio = $profile['bio']; +// Get profile details from DHT } else if ($userProfileVersions = $_twister->getDHT($_SESSION['userName'], 'profile', 's')) { // Add DHT version if not exists foreach ($userProfileVersions as $userProfileVersion) { if (!$_modelProfile->versionExists($_SESSION['userId'], - $userProfileVersion['p']['height'], - $userProfileVersion['p']['seq'])) { + Filter::int($userProfileVersion['p']['height']), + Filter::int($userProfileVersion['p']['seq']))) { - $profile = $userProfileVersion['p']['v']; + if (isset($userProfileVersion['p']['v'])) { - $_modelProfile->add($_SESSION['userId'], - $userProfileVersion['p']['height'], - $userProfileVersion['p']['seq'], - $userProfileVersion['p']['time'], - - isset($profile['fullname']) ? $profile['fullname'] : '', - isset($profile['bio']) ? $profile['bio'] : '', - isset($profile['location']) ? $profile['location'] : '', - isset($profile['url']) ? $profile['url'] : '', - isset($profile['bitmessage']) ? $profile['bitmessage'] : '', - isset($profile['tox']) ? $profile['tox'] : ''); + $profile = $userProfileVersion['p']['v']; + + $_modelProfile->add($_SESSION['userId'], + Filter::int($userProfileVersion['p']['height']), + Filter::int($userProfileVersion['p']['seq']), + Filter::int($userProfileVersion['p']['time']), + + isset($profile['fullname']) ? Filter::string($profile['fullname']) : '', + isset($profile['bio']) ? Filter::string($profile['bio']) : '', + isset($profile['location']) ? Filter::string($profile['location']) : '', + isset($profile['url']) ? Filter::string($profile['url']) : '', + isset($profile['bitmessage']) ? Filter::string($profile['bitmessage']) : '', + isset($profile['tox']) ? Filter::string($profile['tox']) : ''); + } } } @@ -256,7 +260,6 @@ if ($profile = $_memcache->get('api.user.profile.' . $_SESSION['userName'])) { $bio = $profile['bio']; $_memcache->set('api.user.profile.' . $_SESSION['userName'], $profile, MEMCACHE_COMPRESS, MEMCACHE_DHT_PROFILE_TIMEOUT); - } } diff --git a/src/system/helper/filter.php b/src/system/helper/filter.php index fce4a1a..a2fedaf 100644 --- a/src/system/helper/filter.php +++ b/src/system/helper/filter.php @@ -2,13 +2,28 @@ class Filter { - public static function userName(string $userName) { + public static function userName(mixed $userName) { return preg_replace('/[^a-zA-Z0-9_]+/u', '', $userName); } - public static function userPrivateKey(string $userPrivateKey) { + public static function userPrivateKey(mixed $userPrivateKey) { return preg_replace('/[^a-zA-Z0-9_]+/u', '', $userPrivateKey); } + + public static function blockHash(mixed $blockHash) { + + return preg_replace('/[^a-zA-Z0-9]+/u', '', $blockHash); + } + + public static function string(mixed $string) { + + return htmlentities($string, ENT_QUOTES, 'UTF-8'); + } + + public static function int(mixed $int) { + + return (int) $int; + } } diff --git a/tool/crawler/blockchain.php b/tool/crawler/blockchain.php index f84ff10..08878fe 100644 --- a/tool/crawler/blockchain.php +++ b/tool/crawler/blockchain.php @@ -9,6 +9,7 @@ require(PROJECT_DIR . '/application/model/block.php'); require(PROJECT_DIR . '/system/curl.php'); require(PROJECT_DIR . '/system/twister.php'); +require(PROJECT_DIR . '/system/helper/filter.php'); // Init libraries $_twister = new Twister( @@ -51,6 +52,8 @@ while (true) { exit; } + $blockHash = Filter::blockHash($blockHash); + if (!$block = $_twister->getBlock($blockHash)) { trigger_error(sprintf('could not receive block info on %s (%s)', $nextBlock, $blockHash)); @@ -65,6 +68,8 @@ while (true) { // Add users foreach ($block['usernames'] as $userName) { + $userName = Filter::userName($userName); + if (!$_modelUser->addUser($blockId, $userName)) { trigger_error(sprintf('could not add user %s in block %s)', $userName, $blockId)); exit;