N°4384 Security hardening

This commit is contained in:
Pierre Goiffon
2021-11-25 12:59:19 +01:00
parent d8a77c22a3
commit b6fac4b411
3 changed files with 63 additions and 26 deletions

View File

@@ -91,26 +91,34 @@ class ObjectFormManager extends FormManager
* - formmode : view|edit|create
* - values for parent
*
* @param bool $bTrustContent if false then won't allow TWIG content
*
* @inheritDoc
* @throws \Exception
* @throws \SecurityException if twig content is present and $bTrustContent is false
*/
static function FromJSON($sJson)
public static function FromJSON($sJson, $bTrustContent = false)
{
if (is_array($sJson))
{
if (is_array($sJson)) {
$aJson = $sJson;
}
else
{
} else {
$aJson = json_decode($sJson, true);
}
if (false === $bTrustContent) {
/** @noinspection NestedPositiveIfStatementsInspection */
if (isset($aJson['formproperties']['layout']['type']) && ($aJson['formproperties']['layout']['type'] === 'twig')) {
// There will be an IssueLog above in the hierarchy due to the exception, but we are logging here so that we can output the JSON data !
IssueLog::Error('Portal received a query with forbidden twig content!', \LogChannels::PORTAL, ['formmanager_data' => $aJson]);
throw new \SecurityException('Twig content not allowed in this context!');
}
}
/** @var \Combodo\iTop\Portal\Form\ObjectFormManager $oFormManager */
$oFormManager = parent::FromJSON($sJson);
// Retrieving object to edit
if (!isset($aJson['formobject_class']))
{
if (!isset($aJson['formobject_class'])) {
throw new Exception('Object class must be defined in order to generate the form');
}
$sObjectClass = $aJson['formobject_class'];
@@ -151,14 +159,44 @@ class ObjectFormManager extends FormManager
}
// Retrieving callback urls
if (!isset($aJson['formcallbacks']))
{
if (!isset($aJson['formcallbacks'])) {
// TODO
}
return $oFormManager;
}
/**
* @param string $sPostedFormManagerData received data from the browser
* @param array $aOriginalFormProperties data generated server side
*
* @return bool true if the data are identical
*
* @since 2.7.6 3.0.0 N°4384 check formmanager_data
*/
public static function CanTrustFormLayoutContent($sPostedFormManagerData, $aOriginalFormProperties)
{
$aPostedFormManagerData = json_decode($sPostedFormManagerData, true);
$sPostedFormLayoutType = (isset($aPostedFormManagerData['formproperties']['layout']['type'])) ? $aPostedFormManagerData['formproperties']['layout']['type'] : '';
if ($sPostedFormLayoutType === 'xhtml') {
return true;
}
// we need to parse the content so that autoclose tags are returned correctly (`<div />` => `<div></div>`)
$oHtmlDocument = new \DOMDocument();
$sPostedFormLayoutContent = (isset($aPostedFormManagerData['formproperties']['layout']['content'])) ? $aPostedFormManagerData['formproperties']['layout']['content'] : '';
$oHtmlDocument->loadXML('<root>'.$sPostedFormLayoutContent.'</root>');
$sPostedFormLayoutRendered = $oHtmlDocument->saveHTML();
$sOriginalFormLayoutContent = (isset($aOriginalFormProperties['layout']['content'])) ? $aOriginalFormProperties['layout']['content'] : '';
$oHtmlDocument->loadXML('<root>'.$sOriginalFormLayoutContent.'</root>');
$sOriginalFormLayoutContentRendered = $oHtmlDocument->saveHTML();
return ($sPostedFormLayoutRendered === $sOriginalFormLayoutContentRendered);
}
/**
*
* @return \Symfony\Component\DependencyInjection\ContainerInterface

View File

@@ -108,10 +108,10 @@ class ObjectFormHandlerHelper
/**
* @param \Symfony\Component\HttpFoundation\Request $oRequest
* @param string $sMode
* @param string $sObjectClass
* @param string $sObjectId
* @param string $aFormProperties
* @param string $sMode
* @param string $sObjectClass
* @param string $sObjectId
* @param array $aFormProperties
*
* @return array
*
@@ -127,9 +127,10 @@ class ObjectFormHandlerHelper
$bModal = ($oRequest->isXmlHttpRequest() && empty($sOperation));
// - Retrieve form properties
$aOriginalFormProperties = ApplicationHelper::GetLoadedFormFromClass($this->aCombodoPortalInstanceConf['forms'], $sObjectClass, $sMode);
if ($aFormProperties === null)
{
$aFormProperties = ApplicationHelper::GetLoadedFormFromClass($this->aCombodoPortalInstanceConf['forms'], $sObjectClass, $sMode);
$aFormProperties = $aOriginalFormProperties;
}
// - Create and
@@ -281,27 +282,24 @@ class ObjectFormHandlerHelper
$oFormManager->Build();
$aFormData['hidden_fields'] = $oFormManager->GetHiddenFieldsId();
// Check the number of editable fields
// Check the number of editable fields
$aFormData['editable_fields_count'] = $oFormManager->GetForm()->GetEditableFieldCount();
}
else
{
} else {
// Update / Submit / Cancel
/** @var \Combodo\iTop\Portal\Form\ObjectFormManager $sFormManagerClass */
$sFormManagerClass = $this->oRequestManipulator->ReadParam('formmanager_class', '', FILTER_UNSAFE_RAW);
$sFormManagerData = $this->oRequestManipulator->ReadParam('formmanager_data', '', FILTER_UNSAFE_RAW);
if (empty($sFormManagerClass) || empty($sFormManagerData))
{
if (empty($sFormManagerClass) || empty($sFormManagerData)) {
IssueLog::Error(__METHOD__.' at line '.__LINE__.' : Parameters formmanager_class and formamanager_data must be defined.');
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, 'Parameters formmanager_class and formmanager_data must be defined.');
}
/** @var \Combodo\iTop\Portal\Form\ObjectFormManager $oFormManager */
$oFormManager = $sFormManagerClass::FromJSON($sFormManagerData);
$bTrustContent = $sFormManagerClass::CanTrustFormLayoutContent($sFormManagerData, $aOriginalFormProperties);
$oFormManager = $sFormManagerClass::FromJSON($sFormManagerData, $bTrustContent);
$oFormManager->SetContainer($this->oContainer);
// Applying action rules if present
if (($oFormManager->GetActionRulesToken() !== null) && ($oFormManager->GetActionRulesToken() !== ''))
{
if (($oFormManager->GetActionRulesToken() !== null) && ($oFormManager->GetActionRulesToken() !== '')) {
$aActionRules = ContextManipulatorHelper::DecodeRulesToken($oFormManager->GetActionRulesToken());
$oObj = $oFormManager->GetObject();
$this->oContextManipulator->PrepareObject($aActionRules, $oObj);

View File

@@ -40,7 +40,8 @@ abstract class FormManager
* - formrenderer_class : The class of the FormRenderer to use in the FormManager
* - formrenderer_endpoint : The endpoint of the renderer
*
* @param string $sJson
* @param string|string[] $sJson
*
* @return $this
*/
static function FromJSON($sJson)