N°7124 - [SECU] Cross-Site Request Forgery (CSRF) in several iTop pages (finalize implementation)

This commit is contained in:
jf-cbd
2024-06-07 14:18:14 +02:00
parent d4b342a35d
commit 98f946c871
10 changed files with 31 additions and 22 deletions

View File

@@ -87,6 +87,7 @@
{% block pPageScripts %}
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'node_modules/jquery/dist/jquery.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/ajax_hook.js'|add_itop_version }}"></script>
{% if is_development_environment() %}
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'node_modules/jquery-migrate/dist/jquery-migrate.js'|add_itop_version }}"></script>
{% else %}

5
js/ajax_hook.js Normal file
View File

@@ -0,0 +1,5 @@
// add X-Combodo-Ajax for all request (just after jaquery is loaded)
// mandatory for ajax requests with JQuery (CSRF protection)
$(document).ajaxSend(function (event, jqxhr, options) {
jqxhr.setRequestHeader('X-Combodo-Ajax', 'true');
});

View File

@@ -16,11 +16,7 @@ const CombodoCKEditorFeeds = {
return async function(queryText) {
return new Promise( resolve => {
setTimeout( () => {
fetch(options.url + queryText, {
headers: {
'X-Combodo-Ajax': true
}
})
CombodoHTTP.Fetch(options.url + queryText)
.then(response => {
return response.json();
})

View File

@@ -112,12 +112,9 @@ const CombodoCKEditorHandler = {
const formData = new FormData();
formData.append('upload', file);
fetch(uploadUrl, {
CombodoHTTP.Fetch(uploadUrl, {
method: 'POST',
body: formData,
headers: {
'X-Combodo-Ajax': true
},
body: formData
})
.then(response => response.json())
.then(responseData => {

View File

@@ -247,12 +247,8 @@ $(function()
var file = event.target.files[0];
var formData = new FormData();
formData.append('file', file);
fetch(this.options.post_upload_to, {
CombodoHTTP.Fetch(this.options.post_upload_to, {
method: 'POST',
headers: {
'X-Combodo-Ajax': true
},
body: formData
})
.then(response => {

View File

@@ -8,11 +8,6 @@
*/
$(document).ready(function () {
// AJAX calls handling
// - Custom headers
$(document).ajaxSend(function (event, jqxhr, options) {
jqxhr.setRequestHeader('X-Combodo-Ajax', 'true');
});
// - Error messages regarding the error code
$(document).ajaxError(function (event, jqxhr, options) {
// User is not logged in

View File

@@ -1296,6 +1296,23 @@ const CombodoInlineImage = {
}
};
/**
* Abstract Fetch API wrapper to manage AJAX requests in iTop.
*/
const CombodoHTTP = {
/**
* @param {string} sUrl URL to fetch
* @param {Object} oOptions Fetch options
* @return {Promise<Response>}
*/
Fetch: function(sUrl, oOptions) {
oOptions = oOptions || {};
oOptions.headers = oOptions.headers || {};
oOptions.headers['X-Combodo-Ajax'] = true;
return fetch(sUrl, oOptions);
}
}
/**
* Abstract wrapper to manage modal dialogs in iTop.
* Implementations for the various GUIs may vary but APIs are the same.

View File

@@ -29,12 +29,12 @@ 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') {
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) {

View File

@@ -153,6 +153,7 @@ JS
// Used throughout the app.
$this->LinkScriptFromAppRoot('node_modules/jquery/dist/jquery.min.js');
$this->LinkScriptFromAppRoot('js/ajax_hook.js');
$this->LinkScriptFromAppRoot('js/jquery.blockUI.js');
if (utils::IsDevelopmentEnvironment()) // Needed since many other plugins still rely on oldies like $.browser
{

View File

@@ -10,6 +10,7 @@ class OAuthLandingController extends Controller
public function OperationLanding()
{
$this->AddLinkedScript(utils::GetAbsoluteUrlAppRoot().'node_modules/jquery/dist/jquery.min.js');
$this->AddLinkedScript(utils::GetAbsoluteUrlAppRoot().'js/ajax_hook.js');
$this->DisplayPage([], null, static::ENUM_PAGE_TYPE_BASIC_HTML);
}
}