Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x

MTimeProtectedFileStorage.php

Namespace

Drupal\Component\PhpStorage

File

core/lib/Drupal/Component/PhpStorage/MTimeProtectedFileStorage.php

View source
<?php

namespace Drupal\Component\PhpStorage;


/**
 * Stores PHP code in files with securely hashed names.
 *
 * The goal of this class is to ensure that if a PHP file is replaced with
 * an untrusted one, it does not get loaded. Since mtime granularity is 1
 * second, we cannot prevent an attack that happens within one second of the
 * initial save(). However, it is very unlikely for an attacker exploiting an
 * upload or file write vulnerability to also know when a legitimate file is
 * being saved, discover its hash, undo its file permissions, and override the
 * file with an upload all within a single second. Being able to accomplish
 * that would indicate a site very likely vulnerable to many other attack
 * vectors.
 *
 * Each file is stored in its own unique containing directory. The hash is
 * based on the virtual file name, the containing directory's mtime, and a
 * cryptographically hard to guess secret string. Thus, even if the hashed file
 * name is discovered and replaced by an untrusted file (e.g., via a
 * move_uploaded_file() invocation by a script that performs insufficient
 * validation), the directory's mtime gets updated in the process, invalidating
 * the hash and preventing the untrusted file from getting loaded. Also, the
 * file mtime will be checked providing security against overwriting in-place,
 * at the cost of an additional system call for every load() and exists().
 *
 * The containing directory is created with the same name as the virtual file
 * name (slashes replaced with hash marks) to assist with debugging, since the
 * file itself is stored with a name that's meaningless to humans.
 */
class MTimeProtectedFileStorage extends MTimeProtectedFastFileStorage {
    
    /**
     * {@inheritdoc}
     */
    public function load($name) {
        if (($filename = $this->checkFile($name)) !== FALSE) {
            // Inline parent::load() to avoid an expensive getFullPath() call.
            return @(include_once $filename) !== FALSE;
        }
        return FALSE;
    }
    
    /**
     * {@inheritdoc}
     */
    public function exists($name) {
        return $this->checkFile($name) !== FALSE;
    }
    
    /**
     * Determines whether a protected file exists and sets the filename too.
     *
     * @param string $name
     *   The virtual file name. Can be a relative path.
     *
     * @return string|false
     *   The full path where the file is if it is valid, FALSE otherwise.
     */
    protected function checkFile($name) {
        $filename = $this->getFullPath($name, $directory, $directory_mtime);
        return file_exists($filename) && filemtime($filename) <= $directory_mtime ? $filename : FALSE;
    }
    
    /**
     * {@inheritdoc}
     */
    public function getPath($name) {
        return $this->checkFile($name);
    }

}

Classes

Title Deprecated Summary
MTimeProtectedFileStorage Stores PHP code in files with securely hashed names.
RSS feed
Powered by Drupal