PHP 8.0: phar:// stream wrapper no longer unserializes meta data automatically

Version8.0
TypeChange

A security improvement in PHP 8.0 is that the Phar stream wrapper (phar://) no longer automatically calls unserialize on stream wrapper operations, such as file_exists('phar://file.txt').

Prior to PHP 8.0, when the Phar stream wrappers (phar://) were used, it automatically attempted to unserialize the Phar meta data. This behavior could be exploited and expanded to a remote code execution vulnerability because the unserialize function attempts to autoload and instantiate a class, possibly controlled by an attacker.

Calling functions that accepted stream wrappers (fopen, file_exists, etc) with a phar:// URI immediately triggered the unserialize call, which is changed in PHP 8.1.

In PHP 8.1, stream wrapper functions no longer attempt to unserialize meta data. Only explicit calls to Phar::getMetadata and PharFile::getMetadata attempt to unserialize the Phar meta data.


Further, the Phar::getMetadata and PharFileInfo::getMetadata methods now accept an array of unserialization options, that behave similar to the unserialization options parameter in the unserialize function. This allows safer unserialization of meta data by explicitly disallowing all PHP classes. See more information at the unserialize function documentation.

class Phar {
    // ...
-   public function getMetadata() {}
+   public function getMetadata(array $unserializeOptions = []) {}
} 
class PharFileInfo {
    // ...
-   public function getMetadata() {}
+   public function getMetadata(array $unserializeOptions = []) {}
} 

When attempting to retrieve the meta data, it is now possible to neutralize the potential security vulnerabilities from the unserialize call by passing a list of classes that are allowed to be unserialized. Passing an empty array ([]) completely disables class instantiating entirely, which is the highly recommended setting.

$phar = new Phar('path/to/phar.phar');
$phar->getMetadata(['allowed_classes' => []]);

Backwards Compatibility Impact

It is unlikely that a real-life application is broken because of this change. Automatic unserialization on stream wrapper functions is considered an unintended side-effect, which no longer happens in PHP 8.0 and later.

Note that the getMetadata methods continue to call unserialize automatically, and it is not necessary to manually call unserialize function.

Any classes that extend and override Phar::getMetadata and/or PharFileInfo::getMetadata methods must update their signatures to accept the new parameters. On signature mismatches, PHP 8.0 and later throws a fatal error.


Implementation Discussion RFC