‪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;
35 
40 {
44  protected ‪$request;
45 
52  public function ‪getStatus(ServerRequestInterface ‪$request = null): array
53  {
54  $statuses = [
55  'trustedHostsPattern' => $this->‪getTrustedHostsPatternStatus(),
56  'adminUserAccount' => $this->‪getAdminAccountStatus(),
57  'fileDenyPattern' => $this->‪getFileDenyPatternStatus(),
58  'htaccessUpload' => $this->‪getHtaccessUploadStatus(),
59  'exceptionHandler' => $this->‪getExceptionHandlerStatus(),
60  'exportedFiles' => $this->‪getExportedFilesStatus(),
61  ];
62 
63  if (‪$request !== null) {
64  $statuses['encryptedConnectionStatus'] = $this->‪getEncryptedConnectionStatus(‪$request);
65  $lockSslStatus = $this->‪getLockSslStatus(‪$request);
66  if ($lockSslStatus) {
67  $statuses['getLockSslStatus'] = $lockSslStatus;
68  }
69  }
70 
71  return $statuses;
72  }
73 
74  public function ‪getLabel(): string
75  {
76  return 'security';
77  }
78 
82  protected function ‪getEncryptedConnectionStatus(ServerRequestInterface ‪$request): ‪ReportStatus
83  {
84  $value = $this->‪getLanguageService()->getLL('status_ok');
85  $message = '';
86  $severity = ContextualFeedbackSeverity::OK;
87 
88  $normalizedParams = ‪$request->getAttribute('normalizedParams');
89 
90  if (!$normalizedParams->isHttps()) {
91  $value = $this->‪getLanguageService()->getLL('status_insecure');
92  $severity = ContextualFeedbackSeverity::WARNING;
93  $message = $this->‪getLanguageService()->sL('LLL:EXT:reports/Resources/Private/Language/locallang_reports.xlf:status_encryptedConnectionStatus_insecure');
94  }
95 
96  return GeneralUtility::makeInstance(ReportStatus::class, $this->‪getLanguageService()->getLL('status_encryptedConnectionStatus'), $value, $message, $severity);
97  }
98 
102  protected function ‪getLockSslStatus(ServerRequestInterface ‪$request): ?‪ReportStatus
103  {
104  $normalizedParams = ‪$request->getAttribute('normalizedParams');
105 
106  if ($normalizedParams->isHttps()) {
107  $value = $this->‪getLanguageService()->getLL('status_ok');
108  $message = '';
109  $severity = ContextualFeedbackSeverity::OK;
110 
111  if (!‪$GLOBALS['TYPO3_CONF_VARS']['BE']['lockSSL']) {
112  $value = $this->‪getLanguageService()->getLL('status_insecure');
113  $message = $this->‪getLanguageService()->getLL('status_lockSslStatus_insecure');
114  $severity = ContextualFeedbackSeverity::WARNING;
115  }
116 
117  return GeneralUtility::makeInstance(ReportStatus::class, $this->‪getLanguageService()->getLL('status_lockSslStatus'), $value, $message, $severity);
118  }
119 
120  return null;
121  }
122 
129  {
130  $value = $this->‪getLanguageService()->getLL('status_ok');
131  $message = '';
132  $severity = ContextualFeedbackSeverity::OK;
133 
134  if (‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['trustedHostsPattern'] === ‪VerifyHostHeader::ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL) {
135  $value = $this->‪getLanguageService()->getLL('status_insecure');
136  $severity = ContextualFeedbackSeverity::ERROR;
137  $message = $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:warning.install_trustedhosts');
138  }
139 
140  return GeneralUtility::makeInstance(ReportStatus::class, $this->‪getLanguageService()->getLL('status_trustedHostsPattern'), $value, $message, $severity);
141  }
142 
148  protected function ‪getAdminAccountStatus(): ‪ReportStatus
149  {
150  $value = $this->‪getLanguageService()->getLL('status_ok');
151  $message = '';
152  $severity = ContextualFeedbackSeverity::OK;
153 
154  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('be_users');
155  $queryBuilder->getRestrictions()
156  ->removeAll()
157  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
158 
159  $row = $queryBuilder
160  ->select('uid', 'username', 'password')
161  ->from('be_users')
162  ->where(
163  $queryBuilder->expr()->eq(
164  'username',
165  $queryBuilder->createNamedParameter('admin')
166  )
167  )
168  ->executeQuery()
169  ->fetchAssociative();
170 
171  if (!empty($row)) {
172  try {
173  $hashInstance = GeneralUtility::makeInstance(PasswordHashFactory::class)->get($row['password'], 'BE');
174  if ($hashInstance->checkPassword('password', $row['password'])) {
175  // If the password for 'admin' user is 'password': bad idea!
176  // We're checking since the (very) old installer created instances like this in dark old times.
177  $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
178  $value = $this->‪getLanguageService()->getLL('status_insecure');
179  $severity = ContextualFeedbackSeverity::ERROR;
180  $editUserAccountUrl = (string)$uriBuilder->buildUriFromRoute(
181  'record_edit',
182  [
183  'edit[be_users][' . $row['uid'] . ']' => 'edit',
184  'returnUrl' => (string)$uriBuilder->buildUriFromRoute('system_reports'),
185  ]
186  );
187  $message = sprintf(
188  $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:warning.backend_admin'),
189  '<a href="' . htmlspecialchars($editUserAccountUrl) . '">',
190  '</a>'
191  );
192  }
193  } catch (InvalidPasswordHashException $e) {
194  // No hash class handling for current hash could be found. Not good, but ok in this case.
195  }
196  }
197 
198  return GeneralUtility::makeInstance(ReportStatus::class, $this->‪getLanguageService()->getLL('status_adminUserAccount'), $value, $message, $severity);
199  }
200 
206  protected function ‪getFileDenyPatternStatus(): ‪ReportStatus
207  {
208  $value = $this->‪getLanguageService()->getLL('status_ok');
209  $message = '';
210  $severity = ContextualFeedbackSeverity::OK;
211 
212  $fileAccessCheck = GeneralUtility::makeInstance(FileNameValidator::class);
213  if ($fileAccessCheck->missingImportantPatterns()) {
214  $value = $this->‪getLanguageService()->getLL('status_insecure');
215  $severity = ContextualFeedbackSeverity::ERROR;
216  $message = sprintf(
217  $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:warning.file_deny_pattern_partsNotPresent'),
218  '<br /><pre>' . htmlspecialchars($fileAccessCheck::DEFAULT_FILE_DENY_PATTERN) . '</pre><br />'
219  );
220  }
221 
222  return GeneralUtility::makeInstance(ReportStatus::class, $this->‪getLanguageService()->getLL('status_fileDenyPattern'), $value, $message, $severity);
223  }
224 
231  protected function ‪getHtaccessUploadStatus(): ‪ReportStatus
232  {
233  $value = $this->‪getLanguageService()->getLL('status_ok');
234  $message = '';
235  $severity = ContextualFeedbackSeverity::OK;
236 
237  $fileNameAccess = GeneralUtility::makeInstance(FileNameValidator::class);
238  if ($fileNameAccess->customFileDenyPatternConfigured()
239  && $fileNameAccess->isValid('.htaccess')) {
240  $value = $this->‪getLanguageService()->getLL('status_insecure');
241  $severity = ContextualFeedbackSeverity::ERROR;
242  $message = $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:warning.file_deny_htaccess');
243  }
244 
245  return GeneralUtility::makeInstance(ReportStatus::class, $this->‪getLanguageService()->getLL('status_htaccessUploadProtection'), $value, $message, $severity);
246  }
247 
248  protected function ‪getExceptionHandlerStatus(): ‪ReportStatus
249  {
250  $value = $this->‪getLanguageService()->getLL('status_ok');
251  $message = '';
252  $severity = ContextualFeedbackSeverity::OK;
253  if (
254  str_contains(‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['productionExceptionHandler'], 'Debug') ||
255  (‪Environment::getContext()->isProduction() && (int)‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['displayErrors'] === 1)
256  ) {
257  $value = $this->‪getLanguageService()->getLL('status_insecure');
258  $severity = ContextualFeedbackSeverity::ERROR;
259  $message = $this->‪getLanguageService()->getLL('status_exceptionHandler_errorMessage');
260  } elseif ((int)‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['displayErrors'] === 1) {
261  $severity = ContextualFeedbackSeverity::WARNING;
262  $message = $this->‪getLanguageService()->getLL('status_exceptionHandler_warningMessage');
263  }
264  return GeneralUtility::makeInstance(ReportStatus::class, $this->‪getLanguageService()->getLL('status_exceptionHandler'), $value, $message, $severity);
265  }
266 
267  protected function ‪getExportedFilesStatus(): ‪ReportStatus
268  {
269  $value = $this->‪getLanguageService()->getLL('status_ok');
270  $message = '';
271  $severity = ContextualFeedbackSeverity::OK;
272 
273  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_file');
274  $exportedFiles = $queryBuilder
275  ->select('storage', 'identifier')
276  ->from('sys_file')
277  ->where(
278  $queryBuilder->expr()->like(
279  'identifier',
280  $queryBuilder->createNamedParameter('%/_temp_/importexport/%')
281  ),
282  $queryBuilder->expr()->or(
283  $queryBuilder->expr()->like(
284  'identifier',
285  $queryBuilder->createNamedParameter('%.xml')
286  ),
287  $queryBuilder->expr()->like(
288  'identifier',
289  $queryBuilder->createNamedParameter('%.t3d')
290  )
291  ),
292  )
293  ->executeQuery()
294  ->fetchAllAssociative();
295 
296  if (count($exportedFiles) > 0) {
297  $files = [];
298  foreach ($exportedFiles as $exportedFile) {
299  $files[] = '<li>' . htmlspecialchars($exportedFile['storage'] . ':' . $exportedFile['identifier']) . '</li>';
300  }
301 
302  $value = $this->‪getLanguageService()->getLL('status_insecure');
303  $severity = ContextualFeedbackSeverity::WARNING;
304  $message = $this->‪getLanguageService()->getLL('status_exportedFiles_warningMessage');
305  $message .= '<ul>' . implode(PHP_EOL, $files) . '</ul>';
306  $message .= $this->‪getLanguageService()->getLL('status_exportedFiles_warningRecommendation');
307  }
308 
309  return GeneralUtility::makeInstance(ReportStatus::class, $this->‪getLanguageService()->getLL('status_exportedFiles'), $value, $message, $severity);
310  }
311 
312  protected function ‪getLanguageService(): ‪LanguageService
313  {
314  return ‪$GLOBALS['LANG'];
315  }
316 }
‪TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashFactory
Definition: PasswordHashFactory.php:27
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\$request
‪ServerRequestInterface $request
Definition: SecurityStatus.php:43
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\getTrustedHostsPatternStatus
‪ReportStatus getTrustedHostsPatternStatus()
Definition: SecurityStatus.php:127
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\getLockSslStatus
‪ReportStatus getLockSslStatus(ServerRequestInterface $request)
Definition: SecurityStatus.php:101
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\getHtaccessUploadStatus
‪ReportStatus getHtaccessUploadStatus()
Definition: SecurityStatus.php:230
‪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:205
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\getLanguageService
‪getLanguageService()
Definition: SecurityStatus.php:311
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\getLabel
‪getLabel()
Definition: SecurityStatus.php:73
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\getEncryptedConnectionStatus
‪getEncryptedConnectionStatus(ServerRequestInterface $request)
Definition: SecurityStatus.php:81
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\getStatus
‪ReportStatus[] getStatus(ServerRequestInterface $request=null)
Definition: SecurityStatus.php:51
‪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:42
‪TYPO3\CMS\Core\Middleware\VerifyHostHeader\ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL
‪const ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL
Definition: VerifyHostHeader.php:32
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:36
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\getExceptionHandlerStatus
‪getExceptionHandlerStatus()
Definition: SecurityStatus.php:247
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus
Definition: SecurityStatus.php:40
‪TYPO3\CMS\Reports\Report\Status\SecurityStatus\getExportedFilesStatus
‪getExportedFilesStatus()
Definition: SecurityStatus.php:266
‪$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:147
‪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