diff --git a/js/ckeditor.feeds.js b/js/ckeditor.feeds.js index f6bbe312f..b06279602 100644 --- a/js/ckeditor.feeds.js +++ b/js/ckeditor.feeds.js @@ -16,7 +16,11 @@ const CombodoCKEditorFeeds = { return async function(queryText) { return new Promise( resolve => { setTimeout( () => { - fetch(options.url + queryText) + fetch(options.url + queryText, { + headers: { + 'X-Combodo-Ajax': true + } + }) .then(response => { return response.json(); }) diff --git a/js/ckeditor.handler.js b/js/ckeditor.handler.js index 59293f913..390cd29a5 100644 --- a/js/ckeditor.handler.js +++ b/js/ckeditor.handler.js @@ -115,6 +115,9 @@ const CombodoCKEditorHandler = { fetch(uploadUrl, { method: 'POST', body: formData, + headers: { + 'X-Combodo-Ajax': true + }, }) .then(response => response.json()) .then(responseData => { diff --git a/pages/ajax.render.php b/pages/ajax.render.php index 02e346b18..89135c9db 100644 --- a/pages/ajax.render.php +++ b/pages/ajax.render.php @@ -27,6 +27,16 @@ use Combodo\iTop\Service\TemporaryObjects\TemporaryObjectManager; require_once('../approot.inc.php'); + +// check if header contains X-Combodo-Ajax for POST request (CSRF protection for ajax calls) +if (!isset($_SERVER['HTTP_X_COMBODO_AJAX']) && $_SERVER['REQUEST_METHOD'] === 'POST') { + $sReferer = utils::HtmlEntities($_SERVER['HTTP_REFERER']); + IssueLog::Error("Unprotected ajax call from: $sReferer", 'SECURITY'); + header('HTTP/1.1 401 Unauthorized'); + die('Unauthorized access. Please see https://www.itophub.io/wiki/page?id=3_2_0:release:developer#checking_for_the_presence_of_specific_header_in_the_post_to_enhance_protection_against_csrf_attacks'); +} + + function LogErrorMessage($sMsgPrefix, $aContextInfo) { $sCurrentUserLogin = UserRights::GetUser(); $sContextInfo = urldecode(http_build_query($aContextInfo, '', ', '));