Commit b8ef3c6b authored by webchick's avatar webchick

Issue #2140433 by pwolanin, chx, Owen Barton, dstol, Heine, Damien Tournoud:...

Issue #2140433 by pwolanin, chx, Owen Barton, dstol, Heine, Damien Tournoud: Port SA-CORE-2013-003 to Drupal 8.
parent 08a9a799
......@@ -2024,7 +2024,7 @@ function drupal_generate_test_ua($prefix) {
else {
// Generate and save a new hash salt for a test run.
// Consumed by drupal_valid_test_ua() before settings.php is loaded.
$private_key = Crypt::randomStringHashed(55);
$private_key = Crypt::randomBytesBase64(55);
file_put_contents($key_file, $private_key);
}
// The file properties add more entropy not easily accessible to others.
......
<?php
use Drupal\Component\Utility\Crypt;
use Drupal\Component\Utility\Json;
use Drupal\Component\Utility\Number;
use Drupal\Component\Utility\Settings;
......@@ -3195,6 +3196,10 @@ function _drupal_bootstrap_code() {
// Make sure all stream wrappers are registered.
file_get_stream_wrappers();
// Ensure mt_rand() is reseeded to prevent random values from one page load
// being exploited to predict random values in subsequent page loads.
$seed = unpack("L", Crypt::randomBytes(4));
mt_srand($seed[1]);
// Set the allowed protocols once we have the config available.
$allowed_protocols = \Drupal::config('system.filter')->get('protocols');
......@@ -4294,7 +4299,7 @@ function drupal_pre_render_render_cache_placeholder($element) {
if (!is_array($context)) {
throw new Exception(t('#context must be an array.'));
}
$token = \Drupal\Component\Utility\Crypt::randomStringHashed(55);
$token = \Drupal\Component\Utility\Crypt::randomBytesBase64(55);
// Generate placeholder markup and store #post_render_cache callback.
$element['#markup'] = drupal_render_cache_generate_placeholder($callback, $context, $token);
......
......@@ -6,7 +6,7 @@
*/
use Drupal\Core\StreamWrapper\LocalStream;
use Drupal\Component\PhpStorage\MTimeProtectedFastFileStorage;
use Drupal\Component\PhpStorage\FileStorage;
use Drupal\Component\Utility\String;
use Drupal\Core\StreamWrapper\PublicStream;
......@@ -579,17 +579,16 @@ function file_ensure_htaccess() {
/**
* Creates a .htaccess file in the given directory.
*
* @param $directory
* @param string $directory
* The directory.
* @param $private
* FALSE indicates that $directory should be an open and public directory.
* The default is TRUE which indicates a private and protected directory.
*
* @return bool
* TRUE if the .htaccess file could be created or existed already, FALSE
* otherwise.
*/
function file_save_htaccess($directory, $private = TRUE) {
* @param bool $private
* (Optional) FALSE indicates that $directory should be a web-accessible
* directory. Defaults to TRUE which indicates a private directory.
* @param bool $force_overwrite
* (Optional) Set to TRUE to attempt to overwrite the existing .htaccess file
* if one is already present. Defaults to FALSE.
*/
function file_save_htaccess($directory, $private = TRUE, $force_overwrite = FALSE) {
if (file_uri_scheme($directory)) {
$htaccess_path = file_stream_wrapper_uri_normalize($directory . '/.htaccess');
}
......@@ -598,19 +597,11 @@ function file_save_htaccess($directory, $private = TRUE) {
$htaccess_path = $directory . '/.htaccess';
}
if (file_exists($htaccess_path)) {
if (file_exists($htaccess_path) && !$force_overwrite) {
// Short circuit if the .htaccess file already exists.
return TRUE;
}
if ($private) {
// Private .htaccess file.
$htaccess_lines = MTimeProtectedFastFileStorage::HTACCESS;
}
else {
// Public .htaccess file.
$htaccess_lines = "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006\nOptions None\nOptions +FollowSymLinks";
}
$htaccess_lines = file_htaccess_lines($private);
// Write the .htaccess file.
if (file_exists($directory) && is_writable($directory) && file_put_contents($htaccess_path, $htaccess_lines)) {
......@@ -623,6 +614,23 @@ function file_save_htaccess($directory, $private = TRUE) {
}
}
/**
* Returns the standard .htaccess lines that Drupal writes to file directories.
*
* @param bool $private
* (Optional) Set to FALSE to return the .htaccess lines for a web-accessible
* public directory. The default is TRUE, which returns the .htaccess lines
* for a private directory that should not be web-accessible.
*
* @return string
* The desired contents of the .htaccess file.
*
* @see file_create_htaccess()
*/
function file_htaccess_lines($private = TRUE) {
return FileStorage::htaccessLines($private);
}
/**
* Determines whether the URI has a valid scheme for file API operations.
*
......
......@@ -1255,7 +1255,7 @@ function install_settings_form_submit($form, &$form_state) {
'required' => TRUE,
);
$settings['settings']['hash_salt'] = (object) array(
'value' => Crypt::randomStringHashed(55),
'value' => Crypt::randomBytesBase64(55),
'required' => TRUE,
);
// Remember the profile which was used.
......
......@@ -457,7 +457,7 @@ function drupal_install_config_directories() {
// Add a randomized config directory name to settings.php, unless it was
// manually defined in the existing already.
if (empty($config_directories)) {
$config_directories_hash = Crypt::randomStringHashed(55);
$config_directories_hash = Crypt::randomBytesBase64(55);
$settings['config_directories'] = array(
CONFIG_ACTIVE_DIRECTORY => (object) array(
'value' => conf_path() . '/files/config_' . $config_directories_hash . '/active',
......
......@@ -267,10 +267,10 @@ function drupal_session_initialize() {
// Less random sessions (which are much faster to generate) are used for
// anonymous users than are generated in drupal_session_regenerate() when
// a user becomes authenticated.
session_id(Crypt::hashBase64(uniqid(mt_rand(), TRUE)));
session_id(Crypt::randomBytesBase64());
if ($is_https && settings()->get('mixed_mode_sessions', FALSE)) {
$insecure_session_name = substr(session_name(), 1);
$session_id = Crypt::hashBase64(uniqid(mt_rand(), TRUE));
$session_id = Crypt::randomBytesBase64();
$cookies->set($insecure_session_name, $session_id);
}
}
......@@ -369,7 +369,7 @@ function drupal_session_regenerate() {
$old_insecure_session_id = $cookies->get($insecure_session_name);
}
$params = session_get_cookie_params();
$session_id = Crypt::hashBase64(uniqid(mt_rand(), TRUE) . Crypt::randomBytes(55));
$session_id = Crypt::randomBytesBase64();
// If a session cookie lifetime is set, the session will expire
// $params['lifetime'] seconds from the current request. If it is not set,
// it will expire when the browser is closed.
......@@ -381,7 +381,7 @@ function drupal_session_regenerate() {
if (drupal_session_started()) {
$old_session_id = session_id();
}
session_id(Crypt::hashBase64(uniqid(mt_rand(), TRUE) . Crypt::randomBytes(55)));
session_id(Crypt::randomBytesBase64());
if (isset($old_session_id)) {
$params = session_get_cookie_params();
......
......@@ -2,7 +2,7 @@
/**
* @file
* Definition of Drupal\Component\PhpStorage\FileStorage.
* Contains \Drupal\Component\PhpStorage\FileStorage.
*/
namespace Drupal\Component\PhpStorage;
......@@ -53,10 +53,82 @@ public function load($name) {
*/
public function save($name, $code) {
$path = $this->getFullPath($name);
$this->ensureDirectory(dirname($path));
$directory = dirname($path);
if ($this->ensureDirectory($directory)) {
$htaccess_path = $directory . '/.htaccess';
if (!file_exists($htaccess_path) && file_put_contents($htaccess_path, static::htaccessLines())) {
@chmod($htaccess_path, 0444);
}
}
return (bool) file_put_contents($path, $code);
}
/**
* Returns the standard .htaccess lines that Drupal writes to file directories.
*
* This code is located here so this component can be stand-alone, but it is
* also called by file_htaccess_lines().
*
* @param bool $private
* (Optional) Set to FALSE to return the .htaccess lines for an open and
* public directory. The default is TRUE, which returns the .htaccess lines
* for a private and protected directory.
*
* @return string
* The desired contents of the .htaccess file.
*/
public static function htaccessLines($private = TRUE) {
$lines = <<<EOF
# Turn off all options we don't need.
Options None
Options +FollowSymLinks
# Set the catch-all handler to prevent scripts from being executed.
SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006
<Files *>
# Override the handler again if we're run later in the evaluation list.
SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003
</Files>
# If we know how to do it safely, disable the PHP engine entirely.
<IfModule mod_php5.c>
php_flag engine off
</IfModule>
EOF;
if ($private) {
$lines = "Deny from all\n\n" . $lines;
}
return $lines;
}
/**
* Ensures the directory exists, has the right permissions, and a .htaccess.
*
* For compatibility with open_basedir, the requested directory is created
* using a recursion logic that is based on the relative directory path/tree:
* It works from the end of the path recursively back towards the root
* directory, until an existing parent directory is found. From there, the
* subdirectories are created.
*
* @param string $directory
* The directory path.
* @param int $mode
* The mode, permissions, the directory should have.
*
* @return bool
* TRUE if the directory exists or has been created, FALSE otherwise.
*/
protected function ensureDirectory($directory, $mode = 0777) {
if ($this->createDirectory($directory, $mode)) {
$htaccess_path = $directory . '/.htaccess';
if (!file_exists($htaccess_path) && file_put_contents($htaccess_path, static::htaccessLines())) {
@chmod($htaccess_path, 0444);
}
}
}
/**
* Ensures the requested directory exists and has the right permissions.
*
......@@ -76,7 +148,7 @@ public function save($name, $code) {
* @return bool
* TRUE if the directory exists or has been created, FALSE otherwise.
*/
protected function ensureDirectory($directory, $mode = 0777, $is_backwards_recursive = FALSE) {
protected function createDirectory($directory, $mode = 0777, $is_backwards_recursive = FALSE) {
// If the directory exists already, there's nothing to do.
if (is_dir($directory)) {
return TRUE;
......@@ -97,7 +169,7 @@ protected function ensureDirectory($directory, $mode = 0777, $is_backwards_recur
// until an existing directory is hit, and from there, recursively create
// the sub-directories. Only if that recursion succeeds, create the final,
// originally requested subdirectory.
return $this->ensureDirectory($parent, $mode, TRUE) && mkdir($directory) && chmod($directory, $mode);
return $this->createDirectory($parent, $mode, TRUE) && mkdir($directory) && chmod($directory, $mode);
}
/**
......
......@@ -2,7 +2,7 @@
/**
* @file
* Definition of Drupal\Component\PhpStorage\MTimeProtectedFastFileStorage.
* Contains \Drupal\Component\PhpStorage\MTimeProtectedFastFileStorage.
*/
namespace Drupal\Component\PhpStorage;
......@@ -39,13 +39,6 @@
*/
class MTimeProtectedFastFileStorage extends FileStorage {
/**
* The .htaccess code to make a directory private.
*
* Disabling Options Indexes is particularly important.
*/
const HTACCESS="SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006\nDeny from all\nOptions None\nOptions +FollowSymLinks";
/**
* The secret used in the HMAC.
*
......@@ -74,10 +67,6 @@ public function __construct(array $configuration) {
*/
public function save($name, $data) {
$this->ensureDirectory($this->directory);
$htaccess_path = $this->directory . '/.htaccess';
if (!file_exists($htaccess_path) && file_put_contents($htaccess_path, self::HTACCESS)) {
@chmod($htaccess_path, 0444);
}
// Write the file out to a temporary location. Prepend with a '.' to keep it
// hidden from listings and web servers.
......
......@@ -27,30 +27,29 @@ class Crypt {
* A randomly generated string.
*/
public static function randomBytes($count) {
static $random_state, $bytes;
// Initialize on the first call. The contents of $_SERVER includes a mix of
// user-specific and system information that varies a little with each page.
// Further initialize with the somewhat random PHP process ID.
if (!isset($random_state)) {
$random_state = print_r($_SERVER, TRUE) . getmypid();
$bytes = '';
}
if (strlen($bytes) < $count) {
// /dev/urandom is available on many *nix systems and is considered the
// best commonly available pseudo-random source.
if ($fh = @fopen('/dev/urandom', 'rb')) {
// $random_state does not use drupal_static as it stores random bytes.
static $random_state, $bytes, $has_openssl;
$missing_bytes = $count - strlen($bytes);
if ($missing_bytes > 0) {
// openssl_random_pseudo_bytes() will find entropy in a system-dependent
// way.
if (function_exists('openssl_random_pseudo_bytes')) {
$bytes .= openssl_random_pseudo_bytes($missing_bytes);
}
// Else, read directly from /dev/urandom, which is available on many *nix
// systems and is considered cryptographically secure.
elseif ($fh = @fopen('/dev/urandom', 'rb')) {
// PHP only performs buffered reads, so in reality it will always read
// at least 4096 bytes. Thus, it costs nothing extra to read and store
// that much so as to speed any additional invocations.
$bytes .= fread($fh, max(4096, $count));
$bytes .= fread($fh, max(4096, $missing_bytes));
fclose($fh);
}
// openssl_random_pseudo_bytes() will find entropy in a system-dependent
// way.
elseif (function_exists('openssl_random_pseudo_bytes')) {
$bytes .= openssl_random_pseudo_bytes($count - strlen($bytes));
}
// If /dev/urandom is not available or returns no bytes, this loop will
// If we couldn't get enough entropy, this simple hash-based PRNG will
// generate a good set of pseudo-random bytes on any system.
// Note that it may be important that our $random_state is passed
// through hash() prior to being rolled into $output, that the two hash()
......@@ -58,9 +57,23 @@ public static function randomBytes($count) {
// the microtime() - is prepended rather than appended. This is to avoid
// directly leaking $random_state via the $output stream, which could
// allow for trivial prediction of further "random" numbers.
while (strlen($bytes) < $count) {
$random_state = hash('sha256', microtime() . mt_rand() . $random_state);
$bytes .= hash('sha256', mt_rand() . $random_state, TRUE);
if (strlen($bytes) < $count) {
// Initialize on the first call. The contents of $_SERVER includes a mix
// of user-specific and system information that varies a little with
// each page.
if (!isset($random_state)) {
$random_state = print_r($_SERVER, TRUE);
if (function_exists('getmypid')) {
// Further initialize with the somewhat random PHP process ID.
$random_state .= getmypid();
}
$bytes = '';
}
do {
$random_state = hash('sha256', microtime() . mt_rand() . $random_state);
$bytes .= hash('sha256', mt_rand() . $random_state, TRUE);
} while (strlen($bytes) < $count);
}
}
$output = substr($bytes, 0, $count);
......@@ -111,20 +124,18 @@ public static function hashBase64($data) {
}
/**
* Generates a random, base-64 encoded, URL-safe, sha-256 hashed string.
* Returns a URL-safe, base64 encoded string of highly randomized bytes.
*
* @param int $count
* The number of characters (bytes) of the string to be hashed.
* @param $byte_count
* The number of random bytes to fetch and base64 encode.
*
* @return string
* A base-64 encoded sha-256 hash, with + replaced with -, / with _ and
* any = padding characters removed.
* The base64 encoded result will have a length of up to 4 * $byte_count.
*
* @see \Drupal\Component\Utility\Crypt::randomBytes()
* @see \Drupal\Component\Utility\Crypt::hashBase64()
*/
public static function randomStringHashed($count) {
return static::hashBase64(static::randomBytes($count));
public static function randomBytesBase64($count = 32) {
return strtr(base64_encode(static::randomBytes($count)), array('+' => '-', '/' => '_', '=' => ''));
}
}
......@@ -329,7 +329,7 @@ public function rebuildForm($form_id, &$form_state, $old_form = NULL) {
$form['#build_id'] = $old_form['#build_id'];
}
else {
$form['#build_id'] = 'form-' . Crypt::hashBase64(uniqid(mt_rand(), TRUE) . mt_rand());
$form['#build_id'] = 'form-' . Crypt::randomBytesBase64();
}
// #action defaults to request_uri(), but in case of Ajax and other partial
......@@ -672,7 +672,7 @@ public function prepareForm($form_id, &$form, &$form_state) {
// @see self::buildForm()
// @see self::rebuildForm()
if (!isset($form['#build_id'])) {
$form['#build_id'] = 'form-' . Crypt::hashBase64(uniqid(mt_rand(), TRUE) . mt_rand());
$form['#build_id'] = 'form-' . Crypt::randomBytesBase64();
}
$form['form_build_id'] = array(
'#type' => 'hidden',
......
......@@ -64,7 +64,7 @@ public function set($key) {
* The private key.
*/
protected function create() {
return Crypt::randomStringHashed(55);
return Crypt::randomBytesBase64(55);
}
}
......@@ -99,7 +99,7 @@ function testFileCheckDirectoryHandling() {
$this->assertTrue(is_file(file_default_scheme() . '://.htaccess'), 'Successfully re-created the .htaccess file in the files directory.', 'File');
// Verify contents of .htaccess file.
$file = file_get_contents(file_default_scheme() . '://.htaccess');
$this->assertEqual($file, "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006\nOptions None\nOptions +FollowSymLinks", 'The .htaccess file contains the proper content.', 'File');
$this->assertEqual($file, file_htaccess_lines(FALSE), 'The .htaccess file contains the proper content.', 'File');
}
/**
......
......@@ -43,7 +43,10 @@ function testHtaccessSave() {
mkdir($public, 0777, TRUE);
$this->assertTrue(file_save_htaccess($public, FALSE));
$content = file_get_contents($public . '/.htaccess');
$this->assertIdentical($content, "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006\nOptions None\nOptions +FollowSymLinks");
$this->assertTrue(strpos($content, "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006") !== FALSE);
$this->assertTrue(strpos($content, "Options None") !== FALSE);
$this->assertTrue(strpos($content, "Options +FollowSymLinks") !== FALSE);
$this->assertTrue(strpos($content, "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003") !== FALSE);
$this->assertFilePermissions($public . '/.htaccess', 0444);
$this->assertTrue(file_save_htaccess($public, FALSE));
......@@ -52,7 +55,11 @@ function testHtaccessSave() {
mkdir($private, 0777, TRUE);
$this->assertTrue(file_save_htaccess($private));
$content = file_get_contents($private . '/.htaccess');
$this->assertIdentical($content, "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006\nDeny from all\nOptions None\nOptions +FollowSymLinks");
$this->assertTrue(strpos($content, "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006") !== FALSE);
$this->assertTrue(strpos($content, "Deny from all") !== FALSE);
$this->assertTrue(strpos($content, "Options None") !== FALSE);
$this->assertTrue(strpos($content, "Options +FollowSymLinks") !== FALSE);
$this->assertTrue(strpos($content, "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003") !== FALSE);
$this->assertFilePermissions($private . '/.htaccess', 0444);
$this->assertTrue(file_save_htaccess($private));
......@@ -61,7 +68,11 @@ function testHtaccessSave() {
mkdir($stream, 0777, TRUE);
$this->assertTrue(file_save_htaccess($stream));
$content = file_get_contents($stream . '/.htaccess');
$this->assertIdentical($content, "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006\nDeny from all\nOptions None\nOptions +FollowSymLinks");
$this->assertTrue(strpos($content,"SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006") !== FALSE);
$this->assertTrue(strpos($content,"Deny from all") !== FALSE);
$this->assertTrue(strpos($content,"Options None") !== FALSE);
$this->assertTrue(strpos($content,"Options +FollowSymLinks") !== FALSE);
$this->assertTrue(strpos($content, "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003") !== FALSE);
$this->assertFilePermissions($stream . '/.htaccess', 0444);
$this->assertTrue(file_save_htaccess($stream));
......
......@@ -264,6 +264,39 @@ function system_requirements($phase) {
$requirements['settings.php']['title'] = t('Configuration files');
}
// Test the contents of the .htaccess files.
if ($phase == 'runtime') {
// Try to write the .htaccess files first, to prevent false alarms in case
// (for example) the /tmp directory was wiped.
file_ensure_htaccess();
$htaccess_files['public://.htaccess'] = array(
'title' => t('Public files directory'),
'directory' => drupal_realpath('public://'),
);
if (\Drupal::config('system.file')->get('path.private')) {
$htaccess_files['private://.htaccess'] = array(
'title' => t('Private files directory'),
'directory' => drupal_realpath('private://'),
);
}
$htaccess_files['temporary://.htaccess'] = array(
'title' => t('Temporary files directory'),
'directory' => drupal_realpath('temporary://'),
);
foreach ($htaccess_files as $htaccess_file => $info) {
// Check for the string which was added to the recommended .htaccess file
// in the latest security update.
if (!file_exists($htaccess_file) || !($contents = @file_get_contents($htaccess_file)) || strpos($contents, 'Drupal_Security_Do_Not_Remove_See_SA_2013_003') === FALSE) {
$requirements[$htaccess_file] = array(
'title' => $info['title'],
'value' => t('Not fully protected'),
'severity' => REQUIREMENT_ERROR,
'description' => t('See <a href="@url">@url</a> for information about the recommended .htaccess file which should be added to the %directory directory to help protect against arbitrary code execution.', array('@url' => 'http://drupal.org/SA-CORE-2013-003', '%directory' => $info['directory'])),
);
}
}
}
// Report cron status.
if ($phase == 'runtime') {
$cron_config = \Drupal::config('system.cron');
......@@ -560,7 +593,7 @@ function system_install() {
->save();
// Populate the cron key state variable.
$cron_key = Crypt::randomStringHashed(55);
$cron_key = Crypt::randomBytesBase64(55);
\Drupal::state()->set('system.cron_key', $cron_key);
// Populate the site UUID.
......
......@@ -112,7 +112,7 @@ protected function setUp() {
->will($this->returnValue($roles_1_updated));
// Mocked private key + cache services.
$random = Crypt::randomStringHashed(55);
$random = Crypt::randomBytesBase64(55);
$this->private_key = $this->getMockBuilder('Drupal\Core\PrivateKey')
->disableOriginalConstructor()
->setMethods(array('get'))
......@@ -202,7 +202,7 @@ function drupal_get_hash_salt() {
static $salt;
if (!isset($salt)) {
$salt = Drupal\Component\Utility\Crypt::randomStringHashed(55);
$salt = Drupal\Component\Utility\Crypt::randomBytesBase64(55);
}
return $salt;
......
......@@ -366,10 +366,14 @@ function user_password($length = 10) {
// Loop the number of times specified by $length.
for ($i = 0; $i < $length; $i++) {
do {
// Find a secure random number within the range needed.
$index = ord(Crypt::randomBytes(1));
} while ($index > $len);
// Each iteration, pick a random character from the
// allowable string and append it to the password:
$pass .= $allowable_characters[mt_rand(0, $len)];
$pass .= $allowable_characters[$index];
}
return $pass;
......
......@@ -62,7 +62,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
watchdog('user', 'User %name used one-time login link at time %timestamp.', array('%name' => $account->getUsername(), '%timestamp' => $timestamp));
drupal_set_message(t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.'));
// Let the user's password be changed without the current password check.
$token = Crypt::randomStringHashed(55);
$token = Crypt::randomBytesBase64(55);
$_SESSION['pass_reset_' . $user->id()] = $token;
return new RedirectResponse(url('user/' . $user->id() . '/edit', array(
'query' => array('pass-reset-token' => $token),
......
......@@ -80,7 +80,7 @@ function testSecurity() {
// Ensure the root directory for the bin has a .htaccess file denying web
// access.
$this->assertSame(file_get_contents($expected_root_directory . '/.htaccess'), "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006\nDeny from all\nOptions None\nOptions +FollowSymLinks");
$this->assertSame(file_get_contents($expected_root_directory . '/.htaccess'), call_user_func(array($this->storageClass, 'htaccessLines')));
// Ensure that if the file is replaced with an untrusted one (due to another
// script's file upload vulnerability), it does not get loaded. Since mtime
......
......@@ -37,7 +37,7 @@ public static function getInfo() {
*/
function setUp() {
parent::setUp();
$this->key = Crypt::randomStringHashed(55);
$this->key = Crypt::randomBytesBase64(55);
$private_key = $this->getMockBuilder('Drupal\Core\PrivateKey')
->disableOriginalConstructor()
......
......@@ -50,7 +50,7 @@ public static function getInfo() {
*/
public function setUp() {
parent::setUp();
$this->key = Crypt::randomStringHashed(55);
$this->key = Crypt::randomBytesBase64(55);
$this->state = $this->getMock('Drupal\Core\KeyValueStore\StateInterface');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment