[SS-2017-010] Prevent install.php from disclosing system passwords

This commit is contained in:
Damian Mooyman 2017-11-27 18:15:53 +13:00
parent 7c3997344a
commit 7a79cd039a
No known key found for this signature in database
GPG Key ID: 78B823A10DE27D1A
4 changed files with 69 additions and 37 deletions

View File

@ -26,18 +26,23 @@ class InstallConfig
*
* @param array $request Request object
* @param array $databaseClasses Supported database config
* @param bool $realPassword Set to true to get the real password. If false, any non-posted
* password will be redacted as '********'. Note: Posted passwords are considered disclosed and
* never redacted.
* @return array
*/
public function getDatabaseConfig($request, $databaseClasses)
public function getDatabaseConfig($request, $databaseClasses, $realPassword = true)
{
// Get config from request
if (isset($request['db']['type'])) {
$type = $request['db']['type'];
if (isset($request['db'][$type])) {
return array_merge(
[ 'type' => $type ],
$request['db'][$type]
);
$config = $request['db'][$type];
// The posted placeholder must be substituted with the real password
if (isset($config['password']) && $config['password'] === Installer::PASSWORD_PLACEHOLDER) {
$config['password'] = Environment::getEnv('SS_DATABASE_PASSWORD') ?: '';
}
return array_merge([ 'type' => $type ], $config);
}
}
@ -46,8 +51,16 @@ class InstallConfig
'type' => $this->getDatabaseClass($databaseClasses),
'server' => Environment::getEnv('SS_DATABASE_SERVER') ?: 'localhost',
'username' => Environment::getEnv('SS_DATABASE_USERNAME') ?: 'root',
'password' => Environment::getEnv('SS_DATABASE_PASSWORD') ?: '',
'password' => $realPassword
? (Environment::getEnv('SS_DATABASE_PASSWORD') ?: '')
: Installer::PASSWORD_PLACEHOLDER, // Avoid password disclosure
'database' => Environment::getEnv('SS_DATABASE_NAME') ?: 'SS_mysite',
'path' => Environment::getEnv('SS_DATABASE_PATH')
?: Environment::getEnv('SS_SQLITE_DATABASE_PATH') // sqlite compat
?: null,
'key' => Environment::getEnv('SS_DATABASE_KEY')
?: Environment::getEnv('SS_SQLITE_DATABASE_KEY') // sqlite compat
?: null,
];
}
@ -55,17 +68,26 @@ class InstallConfig
* Get admin config from the environment
*
* @param array $request
* @param bool $realPassword Set to true to get the real password. If false, any non-posted
* password will be redacted as '********'. Note: Posted passwords are considered disclosed and
* never redacted.
* @return array
*/
public function getAdminConfig($request)
public function getAdminConfig($request, $realPassword = true)
{
if (isset($request['admin'])) {
$config = $request['admin'];
if (isset($config['password']) && $config['password'] === Installer::PASSWORD_PLACEHOLDER) {
$config['password'] = Environment::getEnv('SS_DEFAULT_ADMIN_PASSWORD') ?: '';
}
return $request['admin'];
}
return [
'username' => Environment::getEnv('SS_DEFAULT_ADMIN_USERNAME') ?: 'admin',
'password' => Environment::getEnv('SS_DEFAULT_ADMIN_PASSWORD') ?: '',
'password' => $realPassword
? (Environment::getEnv('SS_DEFAULT_ADMIN_PASSWORD') ?: '')
: Installer::PASSWORD_PLACEHOLDER, // Avoid password disclosure
];
}

View File

@ -20,6 +20,11 @@ use SilverStripe\Security\Security;
*/
class Installer extends InstallRequirements
{
/**
* value='' attribute placeholder for password fields
*/
const PASSWORD_PLACEHOLDER = '********';
protected function installHeader()
{
?>

View File

@ -123,14 +123,15 @@
echo $checked ? '<div class="dbfields">' : '<div class="dbfields" style="display: none;">';
if(isset($details['fields'])) foreach($details['fields'] as $fieldName => $fieldSpec) {
$fieldTitle = $fieldSpec['title'];
$fieldType = ($fieldName == 'password') ? 'password' : 'text';
// values
$defaultValue = (isset($fieldSpec['default'])) ? $fieldSpec['default'] : null;
if($usingEnv && isset($fieldSpec['envVar']) && $envVar = getenv($fieldSpec['envVar'])) {
$value = $envVar;
} else {
$value = (isset($databaseConfig[$fieldName]) && $databaseConfig['type'] == $class) ? $databaseConfig[$fieldName] : $defaultValue;
}
$fieldType = ($fieldName === 'password') ? 'password' : 'text';
// Get display value
if (isset($databaseConfig[$fieldName]) && $databaseConfig['type'] == $class) {
$value = $databaseConfig[$fieldName];
} elseif (isset($fieldSpec['default'])) {
$value = $fieldSpec['default'];
} else {
$value = null;
}
// attributes
$attrs = array(

View File

@ -56,8 +56,8 @@ foreach ($databaseClasses as $class => $details) {
// Build config from config / environment / request
$config = new InstallConfig();
$databaseConfig = $config->getDatabaseConfig($_REQUEST, $databaseClasses);
$adminConfig = $config->getAdminConfig($_REQUEST);
$databaseConfig = $config->getDatabaseConfig($_REQUEST, $databaseClasses, true);
$adminConfig = $config->getAdminConfig($_REQUEST, true);
$alreadyInstalled = $config->alreadyInstalled();
$silverstripe_version = $config->getFrameworkVersion();
$sendStats = $config->canSendStats($_REQUEST);
@ -107,22 +107,6 @@ if ($installFromCli && ($req->hasErrors() || $dbReq->hasErrors())) {
// Path to client resources (copied through silverstripe/vendor-plugin)
$clientPath = 'resources/silverstripe/framework/src/Dev/Install/client';
// config-form.html vars (placeholder to prevent deletion)
[
$theme,
$clientPath,
$adminConfig,
$usingEnv,
$silverstripe_version,
$locale,
$locales,
$webserverConfigFile,
$hasErrorOtherThanDatabase,
$hasOnlyWarnings, // If warnings but not errors
$phpIniLocation
];
// If already installed, ensure the user clicked "reinstall"
$expectedArg = $alreadyInstalled ? 'reinstall' : 'go';
if ((isset($_REQUEST[$expectedArg]) || $installFromCli)
@ -142,7 +126,27 @@ if ((isset($_REQUEST[$expectedArg]) || $installFromCli)
'admin' => $adminConfig,
'stats' => $sendStats,
]);
// Show the config form
} else {
include(__DIR__ . '/config-form.html');
return;
}
// Sanitise config prior to rendering config-form.html
$databaseConfig = $config->getDatabaseConfig($_REQUEST, $databaseClasses, false);
$adminConfig = $config->getAdminConfig($_REQUEST, false);
// config-form.html vars (placeholder to prevent deletion)
[
$theme,
$clientPath,
$adminConfig,
$databaseConfig,
$usingEnv,
$silverstripe_version,
$locale,
$locales,
$webserverConfigFile,
$hasErrorOtherThanDatabase,
$hasOnlyWarnings, // If warnings but not errors
$phpIniLocation,
];
include(__DIR__ . '/config-form.html');