From 30bf9dcc754918d73b32d54d3b9e619527e3fd35 Mon Sep 17 00:00:00 2001 From: Benni Mack <benni@typo3.org> Date: Tue, 6 Apr 2021 22:04:56 +0200 Subject: [PATCH] [TASK] Limit GET/POST requests of PersistentStorage This change limits the GET request for the PersistentStorage to only "get" and "getAll", where as the others are only working for "post". Since this logic is encapsulated properly in the Persistent JavaScript API, no other parts are affected. Resolves: #93948 Releases: master Change-Id: I965ea4552671c743cabed10c4cd8ad7275532420 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/68715 Tested-by: TYPO3com <noreply@typo3.com> Tested-by: core-ci <typo3@b13.com> Tested-by: Oliver Bartsch <bo@cedev.de> Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de> Reviewed-by: Oliver Bartsch <bo@cedev.de> Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de> --- .../Public/TypeScript/Storage/Persistent.ts | 1 + .../Classes/Controller/UserSettingsController.php | 14 +++++++++++++- .../Public/JavaScript/Storage/Persistent.js | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/Storage/Persistent.ts b/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/Storage/Persistent.ts index 7cd4840b8571..ffb8019d7d86 100644 --- a/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/Storage/Persistent.ts +++ b/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/Storage/Persistent.ts @@ -115,6 +115,7 @@ class Persistent { data: { action: 'clear', }, + method: 'post', }); this.data = false; } diff --git a/typo3/sysext/backend/Classes/Controller/UserSettingsController.php b/typo3/sysext/backend/Classes/Controller/UserSettingsController.php index ba38cc931a25..f5fd82a1fb3e 100644 --- a/typo3/sysext/backend/Classes/Controller/UserSettingsController.php +++ b/typo3/sysext/backend/Classes/Controller/UserSettingsController.php @@ -30,6 +30,11 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; */ class UserSettingsController { + private const ALLOWED_ACTIONS = [ + 'GET' => ['get', 'getAll'], + 'POST' => ['set', 'addToList', 'removeFromList', 'unset', 'clear'] + ]; + /** * Processes all AJAX calls and returns a JSON for the data * @@ -39,7 +44,8 @@ class UserSettingsController public function processAjaxRequest(ServerRequestInterface $request): ResponseInterface { // do the regular / main logic, depending on the action parameter - $action = $request->getParsedBody()['action'] ?? $request->getQueryParams()['action'] ?? ''; + $action = $this->getValidActionFromRequest($request); + $key = $request->getParsedBody()['key'] ?? $request->getQueryParams()['key'] ?? ''; $value = $request->getParsedBody()['value'] ?? $request->getQueryParams()['value'] ?? ''; $backendUserConfiguration = GeneralUtility::makeInstance(BackendUserConfiguration::class); @@ -75,4 +81,10 @@ class UserSettingsController } return (new JsonResponse())->setPayload($content); } + + protected function getValidActionFromRequest(ServerRequestInterface $request): string + { + $action = $request->getParsedBody()['action'] ?? $request->getQueryParams()['action'] ?? ''; + return in_array($action, (self::ALLOWED_ACTIONS[$request->getMethod()] ?? []), true) ? $action : ''; + } } diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/Storage/Persistent.js b/typo3/sysext/backend/Resources/Public/JavaScript/Storage/Persistent.js index cb67399d2319..74fa11f0b771 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/Storage/Persistent.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/Storage/Persistent.js @@ -10,4 +10,4 @@ * * The TYPO3 project - inspiring people to share! */ -var __importDefault=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};define(["require","exports","jquery"],(function(t,e,s){"use strict";s=__importDefault(s);return new class{constructor(){this.data=!1,this.get=t=>{const e=this;if(!1===this.data){let s;return this.loadFromServer().done(()=>{s=e.getRecursiveDataByDeepKey(e.data,t.split("."))}),s}return this.getRecursiveDataByDeepKey(this.data,t.split("."))},this.set=(t,e)=>(!1!==this.data&&(this.data=this.setRecursiveDataByDeepKey(this.data,t.split("."),e)),this.storeOnServer(t,e)),this.addToList=(t,e)=>{const a=this;return s.default.ajax(TYPO3.settings.ajaxUrls.usersettings_process,{data:{action:"addToList",key:t,value:e},method:"post"}).done(t=>{a.data=t})},this.removeFromList=(t,e)=>{const a=this;return s.default.ajax(TYPO3.settings.ajaxUrls.usersettings_process,{data:{action:"removeFromList",key:t,value:e},method:"post"}).done(t=>{a.data=t})},this.unset=t=>{const e=this;return s.default.ajax(TYPO3.settings.ajaxUrls.usersettings_process,{data:{action:"unset",key:t},method:"post"}).done(t=>{e.data=t})},this.clear=()=>{s.default.ajax(TYPO3.settings.ajaxUrls.usersettings_process,{data:{action:"clear"}}),this.data=!1},this.isset=t=>{const e=this.get(t);return null!=e},this.load=t=>{this.data=t},this.loadFromServer=()=>{const t=this;return s.default.ajax(TYPO3.settings.ajaxUrls.usersettings_process,{async:!1,data:{action:"getAll"}}).done(e=>{t.data=e})},this.storeOnServer=(t,e)=>{const a=this;return s.default.ajax(TYPO3.settings.ajaxUrls.usersettings_process,{data:{action:"set",key:t,value:e},method:"post"}).done(t=>{a.data=t})},this.getRecursiveDataByDeepKey=(t,e)=>{if(1===e.length)return(t||{})[e[0]];const s=e.shift();return this.getRecursiveDataByDeepKey(t[s]||{},e)},this.setRecursiveDataByDeepKey=(t,e,s)=>{if(1===e.length)(t=t||{})[e[0]]=s;else{const a=e.shift();t[a]=this.setRecursiveDataByDeepKey(t[a]||{},e,s)}return t}}}})); \ No newline at end of file +var __importDefault=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};define(["require","exports","jquery"],(function(t,e,s){"use strict";s=__importDefault(s);return new class{constructor(){this.data=!1,this.get=t=>{const e=this;if(!1===this.data){let s;return this.loadFromServer().done(()=>{s=e.getRecursiveDataByDeepKey(e.data,t.split("."))}),s}return this.getRecursiveDataByDeepKey(this.data,t.split("."))},this.set=(t,e)=>(!1!==this.data&&(this.data=this.setRecursiveDataByDeepKey(this.data,t.split("."),e)),this.storeOnServer(t,e)),this.addToList=(t,e)=>{const a=this;return s.default.ajax(TYPO3.settings.ajaxUrls.usersettings_process,{data:{action:"addToList",key:t,value:e},method:"post"}).done(t=>{a.data=t})},this.removeFromList=(t,e)=>{const a=this;return s.default.ajax(TYPO3.settings.ajaxUrls.usersettings_process,{data:{action:"removeFromList",key:t,value:e},method:"post"}).done(t=>{a.data=t})},this.unset=t=>{const e=this;return s.default.ajax(TYPO3.settings.ajaxUrls.usersettings_process,{data:{action:"unset",key:t},method:"post"}).done(t=>{e.data=t})},this.clear=()=>{s.default.ajax(TYPO3.settings.ajaxUrls.usersettings_process,{data:{action:"clear"},method:"post"}),this.data=!1},this.isset=t=>{const e=this.get(t);return null!=e},this.load=t=>{this.data=t},this.loadFromServer=()=>{const t=this;return s.default.ajax(TYPO3.settings.ajaxUrls.usersettings_process,{async:!1,data:{action:"getAll"}}).done(e=>{t.data=e})},this.storeOnServer=(t,e)=>{const a=this;return s.default.ajax(TYPO3.settings.ajaxUrls.usersettings_process,{data:{action:"set",key:t,value:e},method:"post"}).done(t=>{a.data=t})},this.getRecursiveDataByDeepKey=(t,e)=>{if(1===e.length)return(t||{})[e[0]];const s=e.shift();return this.getRecursiveDataByDeepKey(t[s]||{},e)},this.setRecursiveDataByDeepKey=(t,e,s)=>{if(1===e.length)(t=t||{})[e[0]]=s;else{const a=e.shift();t[a]=this.setRecursiveDataByDeepKey(t[a]||{},e,s)}return t}}}})); \ No newline at end of file -- GitLab