Skip to content
This repository has been archived by the owner on Sep 10, 2021. It is now read-only.

Commit

Permalink
Revise random number, string, and UUID generation to improve security
Browse files Browse the repository at this point in the history
  • Loading branch information
Jamie Snape committed Dec 8, 2014
1 parent b8bae79 commit 40a1998
Show file tree
Hide file tree
Showing 40 changed files with 288 additions and 127 deletions.
4 changes: 4 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@
"leafo/scssphp": "~0.1.1",
"maennchen/zipstream-php": "~0.2.2",
"michelf/php-markdown": "~1.4.1",
"moontoast/math": "~1.1.0",
"pear-pear.php.net/XML_Serializer": "~0.20.2",
"reprovinci/solr-php-client": "~1.0.3",
"rhumsaa/uuid": "~2.8.0",
"sendgrid/sendgrid": "~2.1.1",
"symfony/console": "~2.5.7",
"zendframework/zendframework1": "~1.12.9"
},
"require-dev": {
Expand All @@ -42,6 +45,7 @@
"ext-imagick": "*",
"ext-ldap": "*",
"ext-memcached": "*",
"ext-openssl": "*",
"ext-zip": "*"
},
"autoload": {
Expand Down
13 changes: 11 additions & 2 deletions core/controllers/InstallController.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class InstallController extends AppController
{
public $_models = array('User', 'Assetstore');
public $_daos = array('Assetstore');
public $_components = array('Utility');
public $_components = array('Random', 'Utility');
public $_forms = array('Install');

/**
Expand Down Expand Up @@ -172,7 +172,16 @@ public function step2Action()
// Must generate and store our password salt before we create our first user
$options = array('allowModifications' => true);
$applicationConfig = new Zend_Config_Ini(CORE_CONFIGS_PATH.'/application.ini', null, $options);
$applicationConfig->global->password->prefix = UtilityComponent::generateRandomString(32);

if (extension_loaded('openssl')) {
$factory = new \RandomLib\Factory();
$generator = $factory->getHighStrengthGenerator();
$prefix = $generator->generateString(32);
} else {
$prefix = $this->Component->Random->generateString(32);
}

$applicationConfig->global->password->prefix = $prefix;
$applicationConfig->global->gravatar = $form->getValue('gravatar');

$writer = new Zend_Config_Writer_Ini();
Expand Down
18 changes: 9 additions & 9 deletions core/controllers/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class UserController extends AppController
'Setting',
);
public $_daos = array('User', 'Folder', 'Folderpolicygroup', 'Folderpolicyuser', 'Group');
public $_components = array('Breadcrumb', 'Date', 'Filter', 'Sortdao');
public $_components = array('Breadcrumb', 'Date', 'Filter', 'Random', 'Sortdao');
public $_forms = array('User');

/** Init Controller */
Expand Down Expand Up @@ -110,7 +110,7 @@ public function recoverpasswordAction()
}
}

$pass = UtilityComponent::generateRandomString(10);
$pass = $this->Component->Random->generateString(32);
$this->User->changePassword($user, $pass);

$url = $this->getServerURL().$this->view->webroot;
Expand Down Expand Up @@ -206,7 +206,7 @@ public function ajaxregisterAction()
$nopass = (bool) $this->getParam('nopassword');
if ($adminCreate && $nopass) {
$form->populate($this->getRequest()->getPost());
$passwd = UtilityComponent::generateRandomString(32);
$passwd = $this->Component->Random->generateString(32);
$form->getElement('password1')->setValue($passwd);
$form->getElement('password2')->setValue($passwd);

Expand Down Expand Up @@ -891,7 +891,7 @@ public function settingsAction()
return;
}

$tmpPath = $this->getDataDirectory('thumbnail').'/'.mt_rand(1, 1000);
$tmpPath = $this->getDataDirectory('thumbnail').'/'.$this->Component->Random->generateInt();
if (!file_exists($this->getDataDirectory('thumbnail'))) {
throw new Zend_Exception(
"Thumbnail path does not exist: ".$this->getDataDirectory('thumbnail')
Expand All @@ -900,15 +900,15 @@ public function settingsAction()
if (!file_exists($tmpPath)) {
mkdir($tmpPath);
}
$tmpPath .= '/'.mt_rand(1, 1000);
$tmpPath .= '/'.$this->Component->Random->generateInt();
if (!file_exists($tmpPath)) {
mkdir($tmpPath);
}
$destionation = $tmpPath."/".mt_rand(1, 1000).'.jpeg';
while (file_exists($destionation)) {
$destionation = $tmpPath."/".mt_rand(1, 1000).'.jpeg';
$destination = $tmpPath."/".$this->Component->Random->generateInt().'.jpg';
while (file_exists($destination)) {
$destination = $tmpPath."/".$this->Component->Random->generateInt().'.jpg';
}
$pathThumbnail = $destionation;
$pathThumbnail = $destination;

list ($x, $y) = getimagesize($path); //--- get size of img ---
$thumb = 32; //--- max. size of thumb ---
Expand Down
5 changes: 4 additions & 1 deletion core/controllers/components/ExportComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ public function exportBitstreams($userDao, $targetDir, $itemIds, $shouldSymLink)

// process the items which pass the ITEM level policy check
if (!empty($revisions)) {
/** @var RandomComponent $randomComponent */
$randomComponent = MidasLoader::loadComponent('Random');

foreach ($revisions as $revision) {
$itemId = $revision->getItemId();
$this->_createItemDirectory($targetDir.'/'.$itemId);
Expand All @@ -142,7 +145,7 @@ public function exportBitstreams($userDao, $targetDir, $itemIds, $shouldSymLink)
// for symbolic link option,if multiple bitstreams (in a single item revision)
// have the same file name, add a '.new' suffix to distinguish them
if (file_exists($dest)) {
$dest .= '.'.mt_rand().'.new';
$dest .= '.'.$randomComponent->generateInt().'.new';
}
if (!symlink($source, $dest)) {
throw new Zend_Exception("Cannot create symlink: ".$dest."linked to".$source);
Expand Down
12 changes: 7 additions & 5 deletions core/controllers/components/HttpuploadComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,18 @@ public function generateToken($args, $dirname = '')
throw new Exception('Failed to create temporary upload dir', MIDAS_HTTPUPLOAD_TMP_DIR_CREATION_FAILED);
}
}
$unique_identifier = 'midas'.uniqid().'-'.md5($args['filename']);
/** @var RandomComponent $randomComponent */
$randomComponent = MidasLoader::loadComponent('Random');
$uniqueIdentifier = $randomComponent->generateString(64);
if ($dirname != '') {
$unique_identifier = $dirname.'/'.$unique_identifier;
$uniqueIdentifier = $dirname.'/'.$uniqueIdentifier;
}
if (file_exists(UtilityComponent::getTempDirectory().'/'.$unique_identifier)) {
if (file_exists(UtilityComponent::getTempDirectory().'/'.$uniqueIdentifier)) {
throw new Exception('Failed to generate upload token', MIDAS_HTTPUPLOAD_UPLOAD_TOKEN_GENERATION_FAILED);
}
touch(UtilityComponent::getTempDirectory().'/'.$unique_identifier);
touch(UtilityComponent::getTempDirectory().'/'.$uniqueIdentifier);

return array('token' => $unique_identifier);
return array('token' => $uniqueIdentifier);
}

/** Handle the upload */
Expand Down
63 changes: 63 additions & 0 deletions core/controllers/components/RandomComponent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php
/*=========================================================================
MIDAS Server
Copyright (c) Kitware SAS. 26 rue Louis Guérin. 69100 Villeurbanne, FRANCE
All rights reserved.
More information http://www.kitware.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.txt
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
=========================================================================*/

/** Random component for generating random numbers. */
class RandomComponent extends AppComponent
{
/** @var \RandomLib\Factory */
protected $_factory = null;

/** @var \RandomLib\Generator */
protected $_generator = null;

/**
* Generate a medium-strength random integer within the given range.
*
* @param int $minimum lower bound of the range
* @param int $maximum upper bound of the range
* @return int
*/
public function generateInt($minimum = 0, $maximum = PHP_INT_MAX)
{
if (is_null($this->_factory)) {
$this->_factory = new \RandomLib\Factory;
$this->_generator = $this->_factory->getMediumStrengthGenerator();
}

return $this->_generator->generateInt($minimum, $maximum);
}

/**
* Generate a medium-strength random string of the given length.
*
* @param int $length length of the generated string
* @param string $characters characters to use to generate the string
* @return string
*/
public function generateString($length, $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
{
if (is_null($this->_factory)) {
$this->_factory = new \RandomLib\Factory;
$this->_generator = $this->_factory->getMediumStrengthGenerator();
}

return $this->_generator->generateString($length, $characters);
}
}
34 changes: 10 additions & 24 deletions core/controllers/components/UtilityComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -315,12 +315,7 @@ public static function safedelete($filename)
/** Function to run a SQL script */
public static function run_sql_from_file($db, $sqlfile)
{
try {
$db->getConnection();
} catch (Zend_Exception $exception) {
throw new Zend_Exception("Unable to connect.");
}

$db->getConnection();
$sql = '';
$lines = file($sqlfile);
foreach ($lines as $line) {
Expand Down Expand Up @@ -630,28 +625,19 @@ public static function getServerURL()
}

/**
* Generate a string of random characters. Seeds RNG within the function using microtime.
* Generate a medium-strength random string of the given length.
*
* @param $length The length of the random string
* @param $alphabet (Optional) The alphabet string; if none provided, uses [a-zA-z0-9]
* @deprecated since 3.3.0
* @param int $length length of the generated string
* @param string $characters characters to use to generate the string
* @return string
*/
public static function generateRandomString($length, $alphabet = null)
public static function generateRandomString($length, $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
{
if (!is_string($alphabet) || empty($alphabet)) {
$alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
}

// Seed RNG with microtime (for lack of something more difficult to guess)
list($usec, $sec) = explode(' ', microtime());
srand((float) $sec + ((float) $usec * 100000));

$salt = '';
$max = strlen($alphabet) - 1;
for ($i = 0; $i < $length; $i++) {
$salt .= substr($alphabet, mt_rand(0, $max), 1);
}
/** @var RandomComponent $randomComponent */
$randomComponent = MidasLoader::loadComponent('Random');

return $salt;
return $randomComponent->generateString($length, $characters);
}

/**
Expand Down
39 changes: 32 additions & 7 deletions core/controllers/components/UuidComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,47 +18,72 @@
limitations under the License.
=========================================================================*/

/** UuidComponent component */
/** UUID component for generating UUIDs and searching by UUID. */
class UuidComponent extends AppComponent
{
/** Get using id */
/**
* Generate a version 4 UUID.
*
* @return string
*/
public function generate()
{
return str_replace('-', '', \Rhumsaa\Uuid\Uuid::uuid4()->toString());
}

/**
* Return a resource given its unique id.
*
* @param string $uuid UUID
* @return false|CommunityDao|FolderDao|ItemDao|ItemRevisionDao|UserDao
*/
public function getByUid($uuid)
{
/** @var CommunityModel $model */
$model = MidasLoader::loadModel('Community');
$dao = $model->getByUuid($uuid);
if ($dao != false) {

if ($dao !== false) {
$dao->resourceType = MIDAS_RESOURCE_COMMUNITY;

return $dao;
}

/** @var FolderModel $model */
$model = MidasLoader::loadModel('Folder');
$dao = $model->getByUuid($uuid);
if ($dao != false) {

if ($dao !== false) {
$dao->resourceType = MIDAS_RESOURCE_FOLDER;

return $dao;
}

/** @var ItemModel $model */
$model = MidasLoader::loadModel('Item');
$dao = $model->getByUuid($uuid);
if ($dao != false) {

if ($dao !== false) {
$dao->resourceType = MIDAS_RESOURCE_ITEM;

return $dao;
}

/** @var ItemRevisionModel $model */
$model = MidasLoader::loadModel('ItemRevision');
$dao = $model->getByUuid($uuid);
if ($dao != false) {

if ($dao !== false) {
$dao->resourceType = MIDAS_RESOURCE_REVISION;

return $dao;
}

/** @var UserModel $model */
$model = MidasLoader::loadModel('User');
$dao = $model->getByUuid($uuid);
if ($dao != false) {

if ($dao !== false) {
$dao->resourceType = MIDAS_RESOURCE_USER;

return $dao;
Expand Down
4 changes: 3 additions & 1 deletion core/controllers/forms/ImportForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ public function createImportForm($assetstores)
$form->setMethod('post');
$form->setAttrib('class', 'importForm');

$randomComponent = MidasLoader::loadComponent('Random');

// Hidden upload id
$uploadId = new Zend_Form_Element_Hidden('uploadid', array('value' => mt_rand()));
$uploadId = new Zend_Form_Element_Hidden('uploadid', array('value' => $randomComponent->generateInt()));
$uploadId->setDecorators(
array(
'ViewHelper',
Expand Down
4 changes: 3 additions & 1 deletion core/models/base/CommunityModelBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@ abstract public function getByFolder($folder);
public function save($dao)
{
if (!isset($dao->uuid) || empty($dao->uuid)) {
$dao->setUuid(uniqid().md5(mt_rand()));
/** @var UuidComponent $uuidComponent */
$uuidComponent = MidasLoader::loadComponent('Uuid');
$dao->setUuid($uuidComponent->generate());
}
$name = $dao->getName();
if (empty($name) && $name !== '0') {
Expand Down
4 changes: 3 additions & 1 deletion core/models/base/ItemModelBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,9 @@ public function delete($dao)
public function save($dao, $metadataChanged = true)
{
if (!isset($dao->uuid) || empty($dao->uuid)) {
$dao->setUuid(uniqid().md5(mt_rand()));
/** @var UuidComponent $uuidComponent */
$uuidComponent = MidasLoader::loadComponent('Uuid');
$dao->setUuid($uuidComponent->generate());
}
if (!isset($dao->date_creation) || empty($dao->date_creation)) {
$dao->setDateCreation(date('Y-m-d H:i:s'));
Expand Down
Loading

0 comments on commit 40a1998

Please sign in to comment.