Skip to content

Commit

Permalink
[BUGFIX] Do not check HTTP referrer anymore
Browse files Browse the repository at this point in the history
Under certain circumstances some browsers do not set the HTTP referrer
anymore due to privacy reasons. Hence, checking the referrer breaks
functionality.

The configuration option [SYS][doNotCheckReferer] is also removed as
it is not needed anymore.

Resolves: #83768
Releases: master, 8.7, 7.6
Change-Id: Ia8f882e07a9e2091ceb38aee814badb97403250d
Reviewed-on: https://review.typo3.org/55556
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Markus Klein <markus.klein@typo3.org>
Tested-by: Markus Klein <markus.klein@typo3.org>
Reviewed-by: Susanne Moog <susanne.moog@typo3.org>
Tested-by: Susanne Moog <susanne.moog@typo3.org>
  • Loading branch information
Michael Schams authored and susannemoog committed Feb 9, 2018
1 parent 63e26be commit b103422
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 181 deletions.
237 changes: 110 additions & 127 deletions typo3/sysext/backend/Classes/Controller/EditDocumentController.php
Original file line number Diff line number Diff line change
Expand Up @@ -557,146 +557,129 @@ public function processData()
if (is_array($this->mirror)) {
$tce->setMirror($this->mirror);
}
// Checking referer / executing
$refInfo = parse_url(GeneralUtility::getIndpEnv('HTTP_REFERER'));
$httpHost = GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY');
if ($httpHost != $refInfo['host']
&& !$GLOBALS['TYPO3_CONF_VARS']['SYS']['doNotCheckReferer']

// Perform the saving operation with DataHandler:
$tce->process_uploads($_FILES);
$tce->process_datamap();
$tce->process_cmdmap();
// If pages are being edited, we set an instruction about updating the page tree after this operation.
if ($tce->pagetreeNeedsRefresh
&& (isset($this->data['pages']) || $beUser->workspace != 0 && !empty($this->data))
) {
$tce->log(
'',
0,
0,
0,
1,
'Referer host \'%s\' and server host \'%s\' did not match!',
1,
[$refInfo['host'], $httpHost]
);
debug('Error: Referer host did not match with server host.');
} else {
// Perform the saving operation with DataHandler:
$tce->process_uploads($_FILES);
$tce->process_datamap();
$tce->process_cmdmap();
// If pages are being edited, we set an instruction about updating the page tree after this operation.
if ($tce->pagetreeNeedsRefresh
&& (isset($this->data['pages']) || $beUser->workspace != 0 && !empty($this->data))
) {
BackendUtility::setUpdateSignal('updatePageTree');
}
// If there was saved any new items, load them:
if (!empty($tce->substNEWwithIDs_table)) {
// save the expanded/collapsed states for new inline records, if any
FormEngineUtility::updateInlineView($this->uc, $tce);
$newEditConf = [];
foreach ($this->editconf as $tableName => $tableCmds) {
$keys = array_keys($tce->substNEWwithIDs_table, $tableName);
if (!empty($keys)) {
foreach ($keys as $key) {
$editId = $tce->substNEWwithIDs[$key];
// Check if the $editId isn't a child record of an IRRE action
if (!(is_array($tce->newRelatedIDs[$tableName])
&& in_array($editId, $tce->newRelatedIDs[$tableName]))
) {
// Translate new id to the workspace version:
if ($versionRec = BackendUtility::getWorkspaceVersionOfRecord(
$beUser->workspace,
$tableName,
$editId,
'uid'
)) {
$editId = $versionRec['uid'];
}
$newEditConf[$tableName][$editId] = 'edit';
}
/** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
$uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
// Traverse all new records and forge the content of ->editconf so we can continue to EDIT
// these records!
if ($tableName === 'pages'
&& $this->retUrl != (string)$uriBuilder->buildUriFromRoute('dummy')
&& $this->returnNewPageId
) {
$this->retUrl .= '&id=' . $tce->substNEWwithIDs[$key];
BackendUtility::setUpdateSignal('updatePageTree');
}
// If there was saved any new items, load them:
if (!empty($tce->substNEWwithIDs_table)) {
// save the expanded/collapsed states for new inline records, if any
FormEngineUtility::updateInlineView($this->uc, $tce);
$newEditConf = [];
foreach ($this->editconf as $tableName => $tableCmds) {
$keys = array_keys($tce->substNEWwithIDs_table, $tableName);
if (!empty($keys)) {
foreach ($keys as $key) {
$editId = $tce->substNEWwithIDs[$key];
// Check if the $editId isn't a child record of an IRRE action
if (!(is_array($tce->newRelatedIDs[$tableName])
&& in_array($editId, $tce->newRelatedIDs[$tableName]))
) {
// Translate new id to the workspace version:
if ($versionRec = BackendUtility::getWorkspaceVersionOfRecord(
$beUser->workspace,
$tableName,
$editId,
'uid'
)) {
$editId = $versionRec['uid'];
}
$newEditConf[$tableName][$editId] = 'edit';
}
/** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
$uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
// Traverse all new records and forge the content of ->editconf so we can continue to EDIT
// these records!
if ($tableName === 'pages'
&& $this->retUrl != (string)$uriBuilder->buildUriFromRoute('dummy')
&& $this->returnNewPageId
) {
$this->retUrl .= '&id=' . $tce->substNEWwithIDs[$key];
}
} else {
$newEditConf[$tableName] = $tableCmds;
}
} else {
$newEditConf[$tableName] = $tableCmds;
}
// Resetting editconf if newEditConf has values:
if (!empty($newEditConf)) {
$this->editconf = $newEditConf;
}
// Finally, set the editconf array in the "getvars" so they will be passed along in URLs as needed.
$this->R_URL_getvars['edit'] = $this->editconf;
// Unsetting default values since we don't need them anymore.
unset($this->R_URL_getvars['defVals']);
// Re-compile the store* values since editconf changed...
$this->compileStoreDat();
}
// See if any records was auto-created as new versions?
if (!empty($tce->autoVersionIdMap)) {
$this->fixWSversioningInEditConf($tce->autoVersionIdMap);
// Resetting editconf if newEditConf has values:
if (!empty($newEditConf)) {
$this->editconf = $newEditConf;
}
// Finally, set the editconf array in the "getvars" so they will be passed along in URLs as needed.
$this->R_URL_getvars['edit'] = $this->editconf;
// Unsetting default values since we don't need them anymore.
unset($this->R_URL_getvars['defVals']);
// Re-compile the store* values since editconf changed...
$this->compileStoreDat();
}
// See if any records was auto-created as new versions?
if (!empty($tce->autoVersionIdMap)) {
$this->fixWSversioningInEditConf($tce->autoVersionIdMap);
}
// If a document is saved and a new one is created right after.
if (isset($_POST['_savedoknew']) && is_array($this->editconf)) {
$this->closeDocument(self::DOCUMENT_CLOSE_MODE_NO_REDIRECT);
// Finding the current table:
reset($this->editconf);
$nTable = key($this->editconf);
// Finding the first id, getting the records pid+uid
reset($this->editconf[$nTable]);
$nUid = key($this->editconf[$nTable]);
$recordFields = 'pid,uid';
if (!empty($GLOBALS['TCA'][$nTable]['ctrl']['versioningWS'])) {
$recordFields .= ',t3ver_oid';
}
// If a document is saved and a new one is created right after.
if (isset($_POST['_savedoknew']) && is_array($this->editconf)) {
$this->closeDocument(self::DOCUMENT_CLOSE_MODE_NO_REDIRECT);
// Finding the current table:
reset($this->editconf);
$nTable = key($this->editconf);
// Finding the first id, getting the records pid+uid
reset($this->editconf[$nTable]);
$nUid = key($this->editconf[$nTable]);
$recordFields = 'pid,uid';
if (!empty($GLOBALS['TCA'][$nTable]['ctrl']['versioningWS'])) {
$recordFields .= ',t3ver_oid';
$nRec = BackendUtility::getRecord($nTable, $nUid, $recordFields);
// Determine insertion mode ('top' is self-explaining,
// otherwise new elements are inserted after one using a negative uid)
$insertRecordOnTop = ($this->getNewIconMode($nTable) === 'top');
// Setting a blank editconf array for a new record:
$this->editconf = [];
// Determine related page ID for regular live context
if ($nRec['pid'] != -1) {
if ($insertRecordOnTop) {
$relatedPageId = $nRec['pid'];
} else {
$relatedPageId = -$nRec['uid'];
}
$nRec = BackendUtility::getRecord($nTable, $nUid, $recordFields);
// Determine insertion mode ('top' is self-explaining,
// otherwise new elements are inserted after one using a negative uid)
$insertRecordOnTop = ($this->getNewIconMode($nTable) === 'top');
// Setting a blank editconf array for a new record:
$this->editconf = [];
// Determine related page ID for regular live context
if ($nRec['pid'] != -1) {
if ($insertRecordOnTop) {
$relatedPageId = $nRec['pid'];
} else {
$relatedPageId = -$nRec['uid'];
}
} else {
// Determine related page ID for workspace context
if ($insertRecordOnTop) {
// Fetch live version of workspace version since the pid value is always -1 in workspaces
$liveRecord = BackendUtility::getRecord($nTable, $nRec['t3ver_oid'], $recordFields);
$relatedPageId = $liveRecord['pid'];
} else {
// Determine related page ID for workspace context
if ($insertRecordOnTop) {
// Fetch live version of workspace version since the pid value is always -1 in workspaces
$liveRecord = BackendUtility::getRecord($nTable, $nRec['t3ver_oid'], $recordFields);
$relatedPageId = $liveRecord['pid'];
} else {
// Use uid of live version of workspace version
$relatedPageId = -$nRec['t3ver_oid'];
}
// Use uid of live version of workspace version
$relatedPageId = -$nRec['t3ver_oid'];
}
$this->editconf[$nTable][$relatedPageId] = 'new';
// Finally, set the editconf array in the "getvars" so they will be passed along in URLs as needed.
$this->R_URL_getvars['edit'] = $this->editconf;
// Re-compile the store* values since editconf changed...
$this->compileStoreDat();
}
// If a preview is requested
if (isset($_POST['_savedokview'])) {
// Get the first table and id of the data array from DataHandler
$table = reset(array_keys($this->data));
$id = reset(array_keys($this->data[$table]));
if (!MathUtility::canBeInterpretedAsInteger($id)) {
$id = $tce->substNEWwithIDs[$id];
}
// Store this information for later use
$this->previewData['table'] = $table;
$this->previewData['id'] = $id;
$this->editconf[$nTable][$relatedPageId] = 'new';
// Finally, set the editconf array in the "getvars" so they will be passed along in URLs as needed.
$this->R_URL_getvars['edit'] = $this->editconf;
// Re-compile the store* values since editconf changed...
$this->compileStoreDat();
}
// If a preview is requested
if (isset($_POST['_savedokview'])) {
// Get the first table and id of the data array from DataHandler
$table = reset(array_keys($this->data));
$id = reset(array_keys($this->data[$table]));
if (!MathUtility::canBeInterpretedAsInteger($id)) {
$id = $tce->substNEWwithIDs[$id];
}
$tce->printLogErrorMessages();
// Store this information for later use
$this->previewData['table'] = $table;
$this->previewData['id'] = $id;
}
$tce->printLogErrorMessages();

// || count($tce->substNEWwithIDs)... If any new items has been save, the document is CLOSED
// because if not, we just get that element re-listed as new. And we don't want that!
if ((int)$this->closeDoc < self::DOCUMENT_CLOSE_MODE_DEFAULT
Expand Down
11 changes: 2 additions & 9 deletions typo3/sysext/backend/Classes/Controller/File/FileController.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,15 +143,8 @@ public function main()
// Initializing:
$this->fileProcessor->setActionPermissions();
$this->fileProcessor->setExistingFilesConflictMode($this->overwriteExistingFiles);
// Checking referrer / executing:
$refInfo = parse_url(GeneralUtility::getIndpEnv('HTTP_REFERER'));
$httpHost = GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY');
if ($httpHost !== $refInfo['host'] && !$GLOBALS['TYPO3_CONF_VARS']['SYS']['doNotCheckReferer']) {
$this->fileProcessor->writeLog(0, 2, 1, 'Referrer host "%s" and server host "%s" did not match!', [$refInfo['host'], $httpHost]);
} else {
$this->fileProcessor->start($this->file);
$this->fileData = $this->fileProcessor->processData();
}
$this->fileProcessor->start($this->file);
$this->fileData = $this->fileProcessor->processData();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,25 +172,18 @@ public function main()
if (is_array($this->mirror)) {
$this->tce->setMirror($this->mirror);
}
// Checking referer / executing
$refInfo = parse_url(GeneralUtility::getIndpEnv('HTTP_REFERER'));
$httpHost = GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY');
if ($httpHost != $refInfo['host'] && !$GLOBALS['TYPO3_CONF_VARS']['SYS']['doNotCheckReferer']) {
$this->tce->log('', 0, 0, 0, 1, 'Referer host "%s" and server host "%s" did not match!', 1, [$refInfo['host'], $httpHost]);
} else {
// Register uploaded files
$this->tce->process_uploads($_FILES);
// Execute actions:
$this->tce->process_datamap();
$this->tce->process_cmdmap();
// Clearing cache:
if (!empty($this->cacheCmd)) {
$this->tce->clear_cacheCmd($this->cacheCmd);
}
// Update page tree?
if (isset($this->data['pages']) || isset($this->cmd['pages'])) {
BackendUtility::setUpdateSignal('updatePageTree');
}
// Register uploaded files
$this->tce->process_uploads($_FILES);
// Execute actions:
$this->tce->process_datamap();
$this->tce->process_cmdmap();
// Clearing cache:
if (!empty($this->cacheCmd)) {
$this->tce->clear_cacheCmd($this->cacheCmd);
}
// Update page tree?
if (isset($this->data['pages']) || isset($this->cmd['pages'])) {
BackendUtility::setUpdateSignal('updatePageTree');
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -596,12 +596,6 @@ public function checkAuthentication()
$this->logger->debug('Active login (eg. with login form)');
// check referrer for submitted login values
if ($this->formfield_status && $loginData['uident'] && $loginData['uname']) {
$httpHost = GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY');
if (!$this->getMethodEnabled && ($httpHost != $authInfo['refInfo']['host'] && !$GLOBALS['TYPO3_CONF_VARS']['SYS']['doNotCheckReferer'])) {
throw new \RuntimeException('TYPO3 Fatal Error: Error: This host address ("' . $httpHost . '") and the referer host ("' . $authInfo['refInfo']['host'] . '") mismatches! ' .
'It is possible that the environment variable HTTP_REFERER is not passed to the script because of a proxy. ' .
'The site administrator can disable this check in the "All Configuration" section of the Install Tool (flag: TYPO3_CONF_VARS[SYS][doNotCheckReferer]).', 1270853930);
}
// Delete old user session if any
$this->logoff();
}
Expand Down
1 change: 0 additions & 1 deletion typo3/sysext/core/Configuration/DefaultConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@
'encryptionKey' => '',
'cookieDomain' => '',
'cookieSecure' => 0,
'doNotCheckReferer' => false,
'recursiveDomainSearch' => false,
'trustedHostsPattern' => 'SERVER_NAME',
'devIPmask' => '127.0.0.1,::1',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,6 @@ SYS:
'1': 'Force HTTPS: the cookie will only be set if a secure (HTTPS) connection exists - use this in combination with lockSSL since otherwise the application will fail and throw an exception'
'2': 'The cookie will be set in each case, but uses the secure flag if a secure (HTTPS) connection exists'
description: 'Indicates that the cookie should only be transmitted over a secure HTTPS connection from the client.'
doNotCheckReferer:
type: bool
description: 'If set, it''s NOT checked numerous places that the referring host is the same as the current. This is an option you should set if you have problems with proxies not passing the HTTP_REFERER variable.'
recursiveDomainSearch:
type: bool
description: 'If set, the search for domain records will be done recursively by stripping parts of the hostname off until a matching domain record is found.'
Expand Down

0 comments on commit b103422

Please sign in to comment.