[FEATURE] Adjust trustedHostsPattern during installation
[Packages/TYPO3.CMS.git] / typo3 / sysext / reports / Classes / Report / Status / SecurityStatus.php
1 <?php
2 namespace TYPO3\CMS\Reports\Report\Status;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Core\Messaging\FlashMessage;
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20 use TYPO3\CMS\Saltedpasswords\Utility\SaltedPasswordsUtility;
21
22 /**
23 * Performs several checks about the system's health
24 */
25 class SecurityStatus implements \TYPO3\CMS\Reports\StatusProviderInterface {
26
27 /**
28 * Determines the security of this TYPO3 installation
29 *
30 * @return \TYPO3\CMS\Reports\Status[] List of statuses
31 */
32 public function getStatus() {
33 $statuses = array(
34 'trustedHostsPattern' => $this->getTrustedHostsPatternStatus(),
35 'adminUserAccount' => $this->getAdminAccountStatus(),
36 'encryptionKeyEmpty' => $this->getEncryptionKeyStatus(),
37 'fileDenyPattern' => $this->getFileDenyPatternStatus(),
38 'htaccessUpload' => $this->getHtaccessUploadStatus(),
39 'saltedpasswords' => $this->getSaltedPasswordsStatus()
40 );
41 return $statuses;
42 }
43
44 /**
45 * Checks if the trusted hosts pattern check is disabled.
46 *
47 * @return \TYPO3\CMS\Reports\Status An object representing whether the check is disabled
48 */
49 protected function getTrustedHostsPatternStatus() {
50 $value = $GLOBALS['LANG']->getLL('status_ok');
51 $message = '';
52 $severity = \TYPO3\CMS\Reports\Status::OK;
53 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['trustedHostsPattern'] === GeneralUtility::ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL) {
54 $value = $GLOBALS['LANG']->getLL('status_insecure');
55 $severity = \TYPO3\CMS\Reports\Status::ERROR;
56 $message = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:warning.install_trustedhosts');
57 }
58 return GeneralUtility::makeInstance(\TYPO3\CMS\Reports\Status::class,
59 $GLOBALS['LANG']->getLL('status_trustedHostsPattern'), $value, $message, $severity);
60 }
61
62 /**
63 * Checks whether a an BE user account named admin with default password exists.
64 *
65 * @return \TYPO3\CMS\Reports\Status An object representing whether a default admin account exists
66 */
67 protected function getAdminAccountStatus() {
68 $value = $GLOBALS['LANG']->getLL('status_ok');
69 $message = '';
70 $severity = \TYPO3\CMS\Reports\Status::OK;
71 $whereClause = 'username = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr('admin', 'be_users') .
72 BackendUtility::deleteClause('be_users');
73 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid, username, password', 'be_users', $whereClause);
74 $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
75 if (!empty($row)) {
76 $secure = TRUE;
77 /** @var $saltingObject \TYPO3\CMS\Saltedpasswords\Salt\SaltInterface */
78 $saltingObject = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance($row['password']);
79 if (is_object($saltingObject)) {
80 if ($saltingObject->checkPassword('password', $row['password'])) {
81 $secure = FALSE;
82 }
83 }
84 // Check against plain MD5
85 if ($row['password'] === '5f4dcc3b5aa765d61d8327deb882cf99') {
86 $secure = FALSE;
87 }
88 if (!$secure) {
89 $value = $GLOBALS['LANG']->getLL('status_insecure');
90 $severity = \TYPO3\CMS\Reports\Status::ERROR;
91 $editUserAccountUrl = BackendUtility::getModuleUrl(
92 'record_edit',
93 array(
94 'edit[be_users][' . $row['uid'] . ']' => 'edit',
95 'returnUrl' => BackendUtility::getModuleUrl('system_ReportsTxreportsm1')
96 )
97 );
98 $message = sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:warning.backend_admin'),
99 '<a href="' . htmlspecialchars($editUserAccountUrl) . '">', '</a>');
100 }
101 }
102 $GLOBALS['TYPO3_DB']->sql_free_result($res);
103 return GeneralUtility::makeInstance(\TYPO3\CMS\Reports\Status::class,
104 $GLOBALS['LANG']->getLL('status_adminUserAccount'), $value, $message, $severity);
105 }
106
107 /**
108 * Checks whether the encryption key is empty.
109 *
110 * @return \TYPO3\CMS\Reports\Status An object representing whether the encryption key is empty or not
111 */
112 protected function getEncryptionKeyStatus() {
113 $value = $GLOBALS['LANG']->getLL('status_ok');
114 $message = '';
115 $severity = \TYPO3\CMS\Reports\Status::OK;
116 if (empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'])) {
117 $value = $GLOBALS['LANG']->getLL('status_insecure');
118 $severity = \TYPO3\CMS\Reports\Status::ERROR;
119 $url = 'install/index.php?redirect_url=index.php' . urlencode('?TYPO3_INSTALL[type]=config#set_encryptionKey');
120 $message = sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:warning.install_encryption'),
121 '<a href="' . $url . '">', '</a>');
122 }
123 return GeneralUtility::makeInstance(\TYPO3\CMS\Reports\Status::class,
124 $GLOBALS['LANG']->getLL('status_encryptionKey'), $value, $message, $severity);
125 }
126
127 /**
128 * Checks if fileDenyPattern was changed which is dangerous on Apache
129 *
130 * @return \TYPO3\CMS\Reports\Status An object representing whether the file deny pattern has changed
131 */
132 protected function getFileDenyPatternStatus() {
133 $value = $GLOBALS['LANG']->getLL('status_ok');
134 $message = '';
135 $severity = \TYPO3\CMS\Reports\Status::OK;
136 $defaultParts = GeneralUtility::trimExplode('|', FILE_DENY_PATTERN_DEFAULT, TRUE);
137 $givenParts = GeneralUtility::trimExplode('|', $GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'], TRUE);
138 $result = array_intersect($defaultParts, $givenParts);
139 if ($defaultParts !== $result) {
140 $value = $GLOBALS['LANG']->getLL('status_insecure');
141 $severity = \TYPO3\CMS\Reports\Status::ERROR;
142 $message = sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:warning.file_deny_pattern_partsNotPresent'),
143 '<br /><pre>' . htmlspecialchars(FILE_DENY_PATTERN_DEFAULT) . '</pre><br />');
144 }
145 return GeneralUtility::makeInstance(\TYPO3\CMS\Reports\Status::class,
146 $GLOBALS['LANG']->getLL('status_fileDenyPattern'), $value, $message, $severity);
147 }
148
149 /**
150 * Checks if fileDenyPattern allows to upload .htaccess files which is
151 * dangerous on Apache.
152 *
153 * @return \TYPO3\CMS\Reports\Status An object representing whether it's possible to upload .htaccess files
154 */
155 protected function getHtaccessUploadStatus() {
156 $value = $GLOBALS['LANG']->getLL('status_ok');
157 $message = '';
158 $severity = \TYPO3\CMS\Reports\Status::OK;
159 if ($GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'] != FILE_DENY_PATTERN_DEFAULT
160 && GeneralUtility::verifyFilenameAgainstDenyPattern('.htaccess')) {
161 $value = $GLOBALS['LANG']->getLL('status_insecure');
162 $severity = \TYPO3\CMS\Reports\Status::ERROR;
163 $message = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:warning.file_deny_htaccess');
164 }
165 return GeneralUtility::makeInstance(\TYPO3\CMS\Reports\Status::class,
166 $GLOBALS['LANG']->getLL('status_htaccessUploadProtection'), $value, $message, $severity);
167 }
168
169 /**
170 * Checks whether memcached is configured, if that's the case we assume it's also used.
171 *
172 * @return bool TRUE if memcached is used, FALSE otherwise.
173 */
174 protected function isMemcachedUsed() {
175 $memcachedUsed = FALSE;
176 $memcachedServers = $this->getConfiguredMemcachedServers();
177 if (!empty($memcachedServers)) {
178 $memcachedUsed = TRUE;
179 }
180 return $memcachedUsed;
181 }
182
183 /**
184 * Checks whether salted Passwords are configured or not.
185 *
186 * @return \TYPO3\CMS\Reports\Status An object representing the security of the saltedpassswords extension
187 */
188 protected function getSaltedPasswordsStatus() {
189 $value = $GLOBALS['LANG']->getLL('status_ok');
190 $severity = \TYPO3\CMS\Reports\Status::OK;
191 /** @var \TYPO3\CMS\Saltedpasswords\Utility\ExtensionManagerConfigurationUtility $configCheck */
192 $configCheck = GeneralUtility::makeInstance(\TYPO3\CMS\Saltedpasswords\Utility\ExtensionManagerConfigurationUtility::class);
193 $message = '<p>' . $GLOBALS['LANG']->getLL('status_saltedPasswords_infoText') . '</p>';
194 $messageDetail = '';
195 $resultCheck = $configCheck->checkConfigurationBackend(array(), new \TYPO3\CMS\Core\TypoScript\ConfigurationForm());
196 switch ($resultCheck['errorType']) {
197 case FlashMessage::INFO:
198 $messageDetail .= $resultCheck['html'];
199 break;
200 case FlashMessage::WARNING;
201 $severity = \TYPO3\CMS\Reports\Status::WARNING;
202 $messageDetail .= $resultCheck['html'];
203 break;
204 case FlashMessage::ERROR:
205 $value = $GLOBALS['LANG']->getLL('status_insecure');
206 $severity = \TYPO3\CMS\Reports\Status::ERROR;
207 $messageDetail .= $resultCheck['html'];
208 break;
209 default:
210 }
211 $unsecureUserCount = SaltedPasswordsUtility::getNumberOfBackendUsersWithInsecurePassword();
212 if ($unsecureUserCount > 0) {
213 $value = $GLOBALS['LANG']->getLL('status_insecure');
214 $severity = \TYPO3\CMS\Reports\Status::ERROR;
215 $messageDetail .= '<div class="panel panel-warning">' .
216 '<div class="panel-body">' .
217 $GLOBALS['LANG']->getLL('status_saltedPasswords_notAllPasswordsHashed') .
218 '</div>' .
219 '</div>';
220 }
221 $message .= $messageDetail;
222 if (empty($messageDetail)) {
223 $message = '';
224 }
225 return GeneralUtility::makeInstance(\TYPO3\CMS\Reports\Status::class,
226 $GLOBALS['LANG']->getLL('status_saltedPasswords'), $value, $message, $severity);
227 }
228
229 }