‪TYPO3CMS  ‪main
SecurityStatus.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Psr\Http\Message\ServerRequestInterface;
34 
39 {
43  protected ‪$request;
44 
51  public function ‪getStatus(ServerRequestInterface ‪$request = null): array
52  {
53  $statuses = [
54  'trustedHostsPattern' => $this->‪getTrustedHostsPatternStatus(),
55  'adminUserAccount' => $this->‪getAdminAccountStatus(),
56  'fileDenyPattern' => $this->‪getFileDenyPatternStatus(),
57  'htaccessUpload' => $this->‪getHtaccessUploadStatus(),
58  'exceptionHandler' => $this->‪getExceptionHandlerStatus(),
59  'exportedFiles' => $this->‪getExportedFilesStatus(),
60  ];
61 
62  if (‪$request !== null) {
63  $statuses['encryptedConnectionStatus'] = $this->‪getEncryptedConnectionStatus(‪$request);
64  $lockSslStatus = $this->‪getLockSslStatus(‪$request);
65  if ($lockSslStatus) {
66  $statuses['getLockSslStatus'] = $lockSslStatus;
67  }
68  }
69 
70  return $statuses;
71  }
72 
73  public function ‪getLabel(): string
74  {
75  return 'security';
76  }
77 
81  protected function ‪getEncryptedConnectionStatus(ServerRequestInterface ‪$request): ‪ReportStatus
82  {
83  $value = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_ok');
84  $message = '';
85  $severity = ContextualFeedbackSeverity::OK;
86 
87  $normalizedParams = ‪$request->getAttribute('normalizedParams');
88 
89  if (!$normalizedParams->isHttps()) {
90  $value = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_insecure');
91  $severity = ContextualFeedbackSeverity::WARNING;
92  $message = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_encryptedConnectionStatus_insecure');
93  }
94 
95  return GeneralUtility::makeInstance(ReportStatus::class, $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_encryptedConnectionStatus'), $value, $message, $severity);
96  }
97 
101  protected function ‪getLockSslStatus(ServerRequestInterface ‪$request): ?‪ReportStatus
102  {
103  $normalizedParams = ‪$request->getAttribute('normalizedParams');
104 
105  if ($normalizedParams->isHttps()) {
106  $value = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_ok');
107  $message = '';
108  $severity = ContextualFeedbackSeverity::OK;
109 
110  if (!‪$GLOBALS['TYPO3_CONF_VARS']['BE']['lockSSL']) {
111  $value = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_insecure');
112  $message = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_lockSslStatus_insecure');
113  $severity = ContextualFeedbackSeverity::WARNING;
114  }
115 
116  return GeneralUtility::makeInstance(ReportStatus::class, $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_lockSslStatus'), $value, $message, $severity);
117  }
118 
119  return null;
120  }
121 
128  {
129  $value = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_ok');
130  $message = '';
131  $severity = ContextualFeedbackSeverity::OK;
132 
133  if (‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['trustedHostsPattern'] === ‪VerifyHostHeader::ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL) {
134  $value = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_insecure');
135  $severity = ContextualFeedbackSeverity::ERROR;
136  $message = $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:warning.install_trustedhosts');
137  }
138 
139  return GeneralUtility::makeInstance(ReportStatus::class, $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_trustedHostsPattern'), $value, $message, $severity);
140  }
141 
147  protected function ‪getAdminAccountStatus(): ‪ReportStatus
148  {
149  $value = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_ok');
150  $message = '';
151  $severity = ContextualFeedbackSeverity::OK;
152 
153  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('be_users');
154  $queryBuilder->getRestrictions()
155  ->removeAll()
156  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
157 
158  $row = $queryBuilder
159  ->select('uid', 'username', 'password')
160  ->from('be_users')
161  ->where(
162  $queryBuilder->expr()->eq(
163  'username',
164  $queryBuilder->createNamedParameter('admin')
165  )
166  )
167  ->executeQuery()
168  ->fetchAssociative();
169 
170  if (!empty($row)) {
171  try {
172  $hashInstance = GeneralUtility::makeInstance(PasswordHashFactory::class)->get($row['password'], 'BE');
173  if ($hashInstance->checkPassword('password', $row['password'])) {
174  // If the password for 'admin' user is 'password': bad idea!
175  // We're checking since the (very) old installer created instances like this in dark old times.
176  $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
177  $value = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_insecure');
178  $severity = ContextualFeedbackSeverity::ERROR;
179  $editUserAccountUrl = (string)$uriBuilder->buildUriFromRoute(
180  'record_edit',
181  [
182  'edit[be_users][' . $row['uid'] . ']' => 'edit',
183  'returnUrl' => (string)$uriBuilder->buildUriFromRoute('system_reports'),
184  ]
185  );
186  $message = sprintf(
187  $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:warning.backend_admin'),
188  '<a href="' . htmlspecialchars($editUserAccountUrl) . '">',
189  '</a>'
190  );
191  }
192  } catch (InvalidPasswordHashException $e) {
193  // No hash class handling for current hash could be found. Not good, but ok in this case.
194  }
195  }
196 
197  return GeneralUtility::makeInstance(ReportStatus::class, $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_adminUserAccount'), $value, $message, $severity);
198  }
199 
205  protected function ‪getFileDenyPatternStatus(): ‪ReportStatus
206  {
207  $value = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_ok');
208  $message = '';
209  $severity = ContextualFeedbackSeverity::OK;
210 
211  $fileAccessCheck = GeneralUtility::makeInstance(FileNameValidator::class);
212  if ($fileAccessCheck->missingImportantPatterns()) {
213  $value = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_insecure');
214  $severity = ContextualFeedbackSeverity::ERROR;
215  $message = sprintf(
216  $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:warning.file_deny_pattern_partsNotPresent'),
217  '<br /><pre>' . htmlspecialchars($fileAccessCheck::DEFAULT_FILE_DENY_PATTERN) . '</pre><br />'
218  );
219  }
220 
221  return GeneralUtility::makeInstance(ReportStatus::class, $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_fileDenyPattern'), $value, $message, $severity);
222  }
223 
230  protected function ‪getHtaccessUploadStatus(): ‪ReportStatus
231  {
232  $value = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_ok');
233  $message = '';
234  $severity = ContextualFeedbackSeverity::OK;
235 
236  $fileNameAccess = GeneralUtility::makeInstance(FileNameValidator::class);
237  if ($fileNameAccess->customFileDenyPatternConfigured()
238  && $fileNameAccess->isValid('.htaccess')) {
239  $value = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_insecure');
240  $severity = ContextualFeedbackSeverity::ERROR;
241  $message = $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:warning.file_deny_htaccess');
242  }
243 
244  return GeneralUtility::makeInstance(ReportStatus::class, $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_htaccessUploadProtection'), $value, $message, $severity);
245  }
246 
247  protected function ‪getExceptionHandlerStatus(): ‪ReportStatus
248  {
249  $value = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_ok');
250  $message = '';
251  $severity = ContextualFeedbackSeverity::OK;
252  if (
253  str_contains(‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['productionExceptionHandler'], 'Debug') ||
254  (‪Environment::getContext()->isProduction() && (int)‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['displayErrors'] === 1)
255  ) {
256  $value = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_insecure');
257  $severity = ContextualFeedbackSeverity::ERROR;
258  $message = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_exceptionHandler_errorMessage');
259  } elseif ((int)‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['displayErrors'] === 1) {
260  $severity = ContextualFeedbackSeverity::WARNING;
261  $message = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_exceptionHandler_warningMessage');
262  }
263  return GeneralUtility::makeInstance(ReportStatus::class, $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_exceptionHandler'), $value, $message, $severity);
264  }
265 
266  protected function ‪getExportedFilesStatus(): ‪ReportStatus
267  {
268  $value = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_ok');
269  $message = '';
270  $severity = ContextualFeedbackSeverity::OK;
271 
272  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_file');
273  $exportedFiles = $queryBuilder
274  ->select('storage', 'identifier')
275  ->from('sys_file')
276  ->where(
277  $queryBuilder->expr()->like(
278  'identifier',
279  $queryBuilder->createNamedParameter('%/_temp_/importexport/%')
280  ),
281  $queryBuilder->expr()->or(
282  $queryBuilder->expr()->like(
283  'identifier',
284  $queryBuilder->createNamedParameter('%.xml')
285  ),
286  $queryBuilder->expr()->like(
287  'identifier',
288  $queryBuilder->createNamedParameter('%.t3d')
289  )
290  ),
291  )
292  ->executeQuery()
293  ->fetchAllAssociative();
294 
295  if (count($exportedFiles) > 0) {
296  $files = [];
297  foreach ($exportedFiles as $exportedFile) {
298  $files[] = '<li>' . htmlspecialchars($exportedFile['storage'] . ':' . $exportedFile['identifier']) . '</li>';
299  }
300 
301  $value = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_insecure');
302  $severity = ContextualFeedbackSeverity::WARNING;
303  $message = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_exportedFiles_warningMessage');
304  $message .= '<ul>' . implode(PHP_EOL, $files) . '</ul>';
305  $message .= $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_exportedFiles_warningRecommendation');
306  }
307 
308  return GeneralUtility::makeInstance(ReportStatus::class, $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_exportedFiles'), $value, $message, $severity);
309  }
310 
311  protected function ‪getLanguageService(): ‪LanguageService
312  {
313  return ‪$GLOBALS['LANG'];
314  }
315 }
‪TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashFactory
Definition: PasswordHashFactory.php:27
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\$request
‪ServerRequestInterface $request
Definition: SecurityStatus.php:42
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\getTrustedHostsPatternStatus
‪ReportStatus getTrustedHostsPatternStatus()
Definition: SecurityStatus.php:126
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\getLockSslStatus
‪ReportStatus getLockSslStatus(ServerRequestInterface $request)
Definition: SecurityStatus.php:100
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\getHtaccessUploadStatus
‪ReportStatus getHtaccessUploadStatus()
Definition: SecurityStatus.php:229
‪TYPO3\CMS\Core\Resource\Security\FileNameValidator
Definition: FileNameValidator.php:25
‪TYPO3\CMS\Core\Crypto\PasswordHashing\InvalidPasswordHashException
Definition: InvalidPasswordHashException.php:26
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\getFileDenyPatternStatus
‪ReportStatus getFileDenyPatternStatus()
Definition: SecurityStatus.php:204
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\getLanguageService
‪getLanguageService()
Definition: SecurityStatus.php:310
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\getLabel
‪getLabel()
Definition: SecurityStatus.php:72
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\getEncryptedConnectionStatus
‪getEncryptedConnectionStatus(ServerRequestInterface $request)
Definition: SecurityStatus.php:80
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\getStatus
‪ReportStatus[] getStatus(ServerRequestInterface $request=null)
Definition: SecurityStatus.php:50
‪TYPO3\CMS\Core\Type\ContextualFeedbackSeverity
‪ContextualFeedbackSeverity
Definition: ContextualFeedbackSeverity.php:25
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy\Reporting\ReportStatus
‪ReportStatus
Definition: ReportStatus.php:24
‪TYPO3\CMS\Reports\Status
Definition: Status.php:24
‪TYPO3\CMS\Reports\StatusProviderInterface\getStatus
‪Status[] getStatus()
‪TYPO3\CMS\Backend\Routing\UriBuilder
Definition: UriBuilder.php:44
‪TYPO3\CMS\Core\Middleware\VerifyHostHeader\ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL
‪const ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL
Definition: VerifyHostHeader.php:32
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\getExceptionHandlerStatus
‪getExceptionHandlerStatus()
Definition: SecurityStatus.php:246
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus
Definition: SecurityStatus.php:39
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\getExportedFilesStatus
‪getExportedFilesStatus()
Definition: SecurityStatus.php:265
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction
Definition: DeletedRestriction.php:28
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:41
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\getAdminAccountStatus
‪ReportStatus getAdminAccountStatus()
Definition: SecurityStatus.php:146
‪TYPO3\CMS\Core\Middleware\VerifyHostHeader
Definition: VerifyHostHeader.php:31
‪TYPO3\CMS\Reports\Report\Status
Definition: ConfigurationStatus.php:16
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:46
‪TYPO3\CMS\Reports\RequestAwareStatusProviderInterface
Definition: RequestAwareStatusProviderInterface.php:26
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:51
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:51
‪TYPO3\CMS\Core\Core\Environment\getContext
‪static getContext()
Definition: Environment.php:128