[BUGFIX] Add missing htmlspecialchars() or quoteJSvalue()
[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\Install\Service\EnableFileService;
21 use TYPO3\CMS\Saltedpasswords\Utility\SaltedPasswordsUtility;
22
23 /**
24 * Performs several checks about the system's health
25 *
26 * @author Ingo Renner <ingo@typo3.org>
27 */
28 class SecurityStatus implements \TYPO3\CMS\Reports\StatusProviderInterface {
29
30 /**
31 * Determines the Install Tool's status, mainly concerning its protection.
32 *
33 * @return array List of statuses
34 */
35 public function getStatus() {
36 $this->executeAdminCommand();
37 $statuses = array(
38 'adminUserAccount' => $this->getAdminAccountStatus(),
39 'encryptionKeyEmpty' => $this->getEncryptionKeyStatus(),
40 'fileDenyPattern' => $this->getFileDenyPatternStatus(),
41 'htaccessUpload' => $this->getHtaccessUploadStatus(),
42 'installToolEnabled' => $this->getInstallToolProtectionStatus(),
43 'installToolPassword' => $this->getInstallToolPasswordStatus(),
44 'saltedpasswords' => $this->getSaltedPasswordsStatus()
45 );
46 return $statuses;
47 }
48
49 /**
50 * Checks whether a an BE user account named admin with default password exists.
51 *
52 * @return \TYPO3\CMS\Reports\Status An object representing whether a default admin account exists
53 */
54 protected function getAdminAccountStatus() {
55 $value = $GLOBALS['LANG']->getLL('status_ok');
56 $message = '';
57 $severity = \TYPO3\CMS\Reports\Status::OK;
58 $whereClause = 'username = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr('admin', 'be_users') .
59 BackendUtility::deleteClause('be_users');
60 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid, username, password', 'be_users', $whereClause);
61 $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
62 if (!empty($row)) {
63 $secure = TRUE;
64 /** @var $saltingObject \TYPO3\CMS\Saltedpasswords\Salt\SaltInterface */
65 $saltingObject = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance($row['password']);
66 if (is_object($saltingObject)) {
67 if ($saltingObject->checkPassword('password', $row['password'])) {
68 $secure = FALSE;
69 }
70 }
71 // Check against plain MD5
72 if ($row['password'] === '5f4dcc3b5aa765d61d8327deb882cf99') {
73 $secure = FALSE;
74 }
75 if (!$secure) {
76 $value = $GLOBALS['LANG']->getLL('status_insecure');
77 $severity = \TYPO3\CMS\Reports\Status::ERROR;
78 $editUserAccountUrl = 'alt_doc.php?returnUrl=' .
79 rawurlencode(BackendUtility::getModuleUrl('system_ReportsTxreportsm1')) . '&edit[be_users][' . $row['uid'] . ']=edit';
80 $message = sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:warning.backend_admin'),
81 '<a href="' . htmlspecialchars($editUserAccountUrl) . '">', '</a>');
82 }
83 }
84 $GLOBALS['TYPO3_DB']->sql_free_result($res);
85 return GeneralUtility::makeInstance(\TYPO3\CMS\Reports\Status::class,
86 $GLOBALS['LANG']->getLL('status_adminUserAccount'), $value, $message, $severity);
87 }
88
89 /**
90 * Checks whether the encryption key is empty.
91 *
92 * @return \TYPO3\CMS\Reports\Status An object representing whether the encryption key is empty or not
93 */
94 protected function getEncryptionKeyStatus() {
95 $value = $GLOBALS['LANG']->getLL('status_ok');
96 $message = '';
97 $severity = \TYPO3\CMS\Reports\Status::OK;
98 if (empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'])) {
99 $value = $GLOBALS['LANG']->getLL('status_insecure');
100 $severity = \TYPO3\CMS\Reports\Status::ERROR;
101 $url = 'install/index.php?redirect_url=index.php' . urlencode('?TYPO3_INSTALL[type]=config#set_encryptionKey');
102 $message = sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:warning.install_encryption'),
103 '<a href="' . $url . '">', '</a>');
104 }
105 return GeneralUtility::makeInstance(\TYPO3\CMS\Reports\Status::class,
106 $GLOBALS['LANG']->getLL('status_encryptionKey'), $value, $message, $severity);
107 }
108
109 /**
110 * Checks if fileDenyPattern was changed which is dangerous on Apache
111 *
112 * @return \TYPO3\CMS\Reports\Status An object representing whether the file deny pattern has changed
113 */
114 protected function getFileDenyPatternStatus() {
115 $value = $GLOBALS['LANG']->getLL('status_ok');
116 $message = '';
117 $severity = \TYPO3\CMS\Reports\Status::OK;
118 $defaultParts = GeneralUtility::trimExplode('|', FILE_DENY_PATTERN_DEFAULT, TRUE);
119 $givenParts = GeneralUtility::trimExplode('|', $GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'], TRUE);
120 $result = array_intersect($defaultParts, $givenParts);
121 if ($defaultParts !== $result) {
122 $value = $GLOBALS['LANG']->getLL('status_insecure');
123 $severity = \TYPO3\CMS\Reports\Status::ERROR;
124 $url = 'install/index.php?redirect_url=index.php' . urlencode('?TYPO3_INSTALL[type]=config#set_encryptionKey');
125 $message = sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:warning.file_deny_pattern_partsNotPresent'),
126 '<br /><pre>' . htmlspecialchars(FILE_DENY_PATTERN_DEFAULT) . '</pre><br />');
127 }
128 return GeneralUtility::makeInstance(\TYPO3\CMS\Reports\Status::class,
129 $GLOBALS['LANG']->getLL('status_fileDenyPattern'), $value, $message, $severity);
130 }
131
132 /**
133 * Checks if fileDenyPattern allows to upload .htaccess files which is
134 * dangerous on Apache.
135 *
136 * @return \TYPO3\CMS\Reports\Status An object representing whether it's possible to upload .htaccess files
137 */
138 protected function getHtaccessUploadStatus() {
139 $value = $GLOBALS['LANG']->getLL('status_ok');
140 $message = '';
141 $severity = \TYPO3\CMS\Reports\Status::OK;
142 if ($GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'] != FILE_DENY_PATTERN_DEFAULT
143 && GeneralUtility::verifyFilenameAgainstDenyPattern('.htaccess')) {
144 $value = $GLOBALS['LANG']->getLL('status_insecure');
145 $severity = \TYPO3\CMS\Reports\Status::ERROR;
146 $message = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:warning.file_deny_htaccess');
147 }
148 return GeneralUtility::makeInstance(\TYPO3\CMS\Reports\Status::class,
149 $GLOBALS['LANG']->getLL('status_htaccessUploadProtection'), $value, $message, $severity);
150 }
151
152 /**
153 * Checks whether memcached is configured, if that's the case we assume it's also used.
154 *
155 * @return bool TRUE if memcached is used, FALSE otherwise.
156 */
157 protected function isMemcachedUsed() {
158 $memcachedUsed = FALSE;
159 $memcachedServers = $this->getConfiguredMemcachedServers();
160 if (count($memcachedServers)) {
161 $memcachedUsed = TRUE;
162 }
163 return $memcachedUsed;
164 }
165
166 /**
167 * Executes commands like removing the Install Tool enable file.
168 *
169 * @return void
170 */
171 protected function executeAdminCommand() {
172 $command = GeneralUtility::_GET('adminCmd');
173 switch ($command) {
174 case 'remove_ENABLE_INSTALL_TOOL':
175 EnableFileService::removeInstallToolEnableFile();
176 break;
177 default:
178 // Do nothing
179 }
180 }
181
182 /**
183 * Checks whether the Install Tool password is set to its default value.
184 *
185 * @return \TYPO3\CMS\Reports\Status An object representing the security of the install tool password
186 */
187 protected function getInstallToolPasswordStatus() {
188 $value = $GLOBALS['LANG']->getLL('status_ok');
189 $message = '';
190 $severity = \TYPO3\CMS\Reports\Status::OK;
191 $validPassword = TRUE;
192 $installToolPassword = $GLOBALS['TYPO3_CONF_VARS']['BE']['installToolPassword'];
193 $saltFactory = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance($installToolPassword);
194 if (is_object($saltFactory)) {
195 $validPassword = !$saltFactory->checkPassword('joh316', $installToolPassword);
196 } elseif ($installToolPassword === md5('joh316')) {
197 $validPassword = FALSE;
198 }
199 if (!$validPassword) {
200 $value = $GLOBALS['LANG']->getLL('status_insecure');
201 $severity = \TYPO3\CMS\Reports\Status::ERROR;
202 $changeInstallToolPasswordUrl = BackendUtility::getModuleUrl('system_InstallInstall');
203 $message = sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:warning.installtool_default_password'),
204 '<a href="' . htmlspecialchars($changeInstallToolPasswordUrl) . '">', '</a>');
205 }
206 return GeneralUtility::makeInstance(\TYPO3\CMS\Reports\Status::class,
207 $GLOBALS['LANG']->getLL('status_installToolPassword'), $value, $message, $severity);
208 }
209
210 /**
211 * Checks whether the Install Tool password is set to its default value.
212 *
213 * @return \TYPO3\CMS\Reports\Status An object representing the security of the saltedpassswords extension
214 */
215 protected function getSaltedPasswordsStatus() {
216 $value = $GLOBALS['LANG']->getLL('status_ok');
217 $severity = \TYPO3\CMS\Reports\Status::OK;
218 /** @var \TYPO3\CMS\Saltedpasswords\Utility\ExtensionManagerConfigurationUtility $configCheck */
219 $configCheck = GeneralUtility::makeInstance(\TYPO3\CMS\Saltedpasswords\Utility\ExtensionManagerConfigurationUtility::class);
220 $message = '<p>' . $GLOBALS['LANG']->getLL('status_saltedPasswords_infoText') . '</p>';
221 $messageDetail = '';
222 $resultCheck = $configCheck->checkConfigurationBackend(array(), new \TYPO3\CMS\Core\TypoScript\ConfigurationForm());
223 switch ($resultCheck['errorType']) {
224 case FlashMessage::INFO:
225 $messageDetail .= $resultCheck['html'];
226 break;
227 case FlashMessage::WARNING;
228 $severity = \TYPO3\CMS\Reports\Status::WARNING;
229 $messageDetail .= $resultCheck['html'];
230 break;
231 case FlashMessage::ERROR:
232 $value = $GLOBALS['LANG']->getLL('status_insecure');
233 $severity = \TYPO3\CMS\Reports\Status::ERROR;
234 $messageDetail .= $resultCheck['html'];
235 break;
236 default:
237 }
238 $unsecureUserCount = SaltedPasswordsUtility::getNumberOfBackendUsersWithInsecurePassword();
239 if ($unsecureUserCount > 0) {
240 $value = $GLOBALS['LANG']->getLL('status_insecure');
241 $severity = \TYPO3\CMS\Reports\Status::ERROR;
242 $messageDetail .= '<div class="panel panel-warning">' .
243 '<div class="panel-body">' .
244 $GLOBALS['LANG']->getLL('status_saltedPasswords_notAllPasswordsHashed') .
245 '</div>' .
246 '</div>';
247 }
248 $message .= $messageDetail;
249 if (empty($messageDetail)) {
250 $message = '';
251 }
252 return GeneralUtility::makeInstance(\TYPO3\CMS\Reports\Status::class,
253 $GLOBALS['LANG']->getLL('status_saltedPasswords'), $value, $message, $severity);
254 }
255
256 /**
257 * Checks for the existence of the ENABLE_INSTALL_TOOL file.
258 *
259 * @return \TYPO3\CMS\Reports\Status An object representing whether ENABLE_INSTALL_TOOL exists
260 */
261 protected function getInstallToolProtectionStatus() {
262 $enableInstallToolFile = PATH_site . 'typo3conf/ENABLE_INSTALL_TOOL';
263 $value = $GLOBALS['LANG']->getLL('status_disabled');
264 $message = '';
265 $severity = \TYPO3\CMS\Reports\Status::OK;
266 if (EnableFileService::installToolEnableFileExists()) {
267 if (EnableFileService::isInstallToolEnableFilePermanent()) {
268 $severity = \TYPO3\CMS\Reports\Status::WARNING;
269 $disableInstallToolUrl = GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL') . '&amp;adminCmd=remove_ENABLE_INSTALL_TOOL';
270 $value = $GLOBALS['LANG']->getLL('status_enabledPermanently');
271 $message = sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:warning.install_enabled'),
272 '<span style="white-space: nowrap;">' . $enableInstallToolFile . '</span>');
273 $message .= ' <a href="' . $disableInstallToolUrl . '">' .
274 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:warning.install_enabled_cmd') . '</a>';
275 } else {
276 if (EnableFileService::installToolEnableFileLifetimeExpired()) {
277 EnableFileService::removeInstallToolEnableFile();
278 } else {
279 $severity = \TYPO3\CMS\Reports\Status::NOTICE;
280 $disableInstallToolUrl = GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL') . '&amp;adminCmd=remove_ENABLE_INSTALL_TOOL';
281 $value = $GLOBALS['LANG']->getLL('status_enabledTemporarily');
282 $message = sprintf($GLOBALS['LANG']->getLL('status_installEnabledTemporarily'),
283 '<span style="white-space: nowrap;">' . $enableInstallToolFile . '</span>', floor($enableInstallToolFileTtl / 60));
284 $message .= ' <a href="' . $disableInstallToolUrl . '">' .
285 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:warning.install_enabled_cmd') . '</a>';
286 }
287 }
288 }
289 return GeneralUtility::makeInstance(\TYPO3\CMS\Reports\Status::class,
290 $GLOBALS['LANG']->getLL('status_installTool'), $value, $message, $severity);
291 }
292 }