annotate vendor/typo3/phar-stream-wrapper/README.md @ 17:129ea1e6d783

Update, including to Drupal core 8.6.10
author Chris Cannam
date Thu, 28 Feb 2019 13:21:36 +0000
parents
children af1871eacc83
rev   line source
Chris@17 1 [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/TYPO3/phar-stream-wrapper/badges/quality-score.png?b=v2)](https://scrutinizer-ci.com/g/TYPO3/phar-stream-wrapper/?branch=v2)
Chris@17 2 [![Travis CI Build Status](https://travis-ci.org/TYPO3/phar-stream-wrapper.svg?branch=v2)](https://travis-ci.org/TYPO3/phar-stream-wrapper)
Chris@17 3
Chris@17 4 # PHP Phar Stream Wrapper
Chris@17 5
Chris@17 6 ## Abstract & History
Chris@17 7
Chris@17 8 Based on Sam Thomas' findings concerning
Chris@17 9 [insecure deserialization in combination with obfuscation strategies](https://blog.secarma.co.uk/labs/near-phar-dangerous-unserialization-wherever-you-are)
Chris@17 10 allowing to hide Phar files inside valid image resources, the TYPO3 project
Chris@17 11 decided back then to introduce a `PharStreamWrapper` to intercept invocations
Chris@17 12 of the `phar://` stream in PHP and only allow usage for defined locations in
Chris@17 13 the file system.
Chris@17 14
Chris@17 15 Since the TYPO3 mission statement is **inspiring people to share**, we thought
Chris@17 16 it would be helpful for others to release our `PharStreamWrapper` as standalone
Chris@17 17 package to the PHP community.
Chris@17 18
Chris@17 19 The mentioned security issue was reported to TYPO3 on 10th June 2018 by Sam Thomas
Chris@17 20 and has been addressed concerning the specific attack vector and for this generic
Chris@17 21 `PharStreamWrapper` in TYPO3 versions 7.6.30 LTS, 8.7.17 LTS and 9.3.1 on 12th
Chris@17 22 July 2018.
Chris@17 23
Chris@17 24 * https://typo3.org/security/advisory/typo3-core-sa-2018-002/
Chris@17 25 * https://blog.secarma.co.uk/labs/near-phar-dangerous-unserialization-wherever-you-are
Chris@17 26 * https://youtu.be/GePBmsNJw6Y
Chris@17 27
Chris@17 28 ## License
Chris@17 29
Chris@17 30 In general the TYPO3 core is released under the GNU General Public License version
Chris@17 31 2 or any later version (`GPL-2.0-or-later`). In order to avoid licensing issues and
Chris@17 32 incompatibilities this `PharStreamWrapper` is licenced under the MIT License. In case
Chris@17 33 you duplicate or modify source code, credits are not required but really appreciated.
Chris@17 34
Chris@17 35 ## Credits
Chris@17 36
Chris@17 37 Thanks to [Alex Pott](https://github.com/alexpott), Drupal for creating
Chris@17 38 back-ports of all sources in order to provide compatibility with PHP v5.3.
Chris@17 39
Chris@17 40 ## Installation
Chris@17 41
Chris@17 42 The `PharStreamWrapper` is provided as composer package `typo3/phar-stream-wrapper`
Chris@17 43 and has minimum requirements of PHP v5.3 ([`v2`](https://github.com/TYPO3/phar-stream-wrapper/tree/v2) branch) and PHP v7.0 ([`master`](https://github.com/TYPO3/phar-stream-wrapper) branch).
Chris@17 44
Chris@17 45 ### Installation for PHP v7.0
Chris@17 46
Chris@17 47 ```
Chris@17 48 composer require typo3/phar-stream-wrapper ^3.0
Chris@17 49 ```
Chris@17 50
Chris@17 51 ### Installation for PHP v5.3
Chris@17 52
Chris@17 53 ```
Chris@17 54 composer require typo3/phar-stream-wrapper ^2.0
Chris@17 55 ```
Chris@17 56
Chris@17 57 ## Example
Chris@17 58
Chris@17 59 The following example is bundled within this package, the shown
Chris@17 60 `PharExtensionInterceptor` denies all stream wrapper invocations files
Chris@17 61 not having the `.phar` suffix. Interceptor logic has to be individual and
Chris@17 62 adjusted to according requirements.
Chris@17 63
Chris@17 64 ```
Chris@17 65 $behavior = new \TYPO3\PharStreamWrapper\Behavior();
Chris@17 66 Manager::initialize(
Chris@17 67 $behavior->withAssertion(new PharExtensionInterceptor())
Chris@17 68 );
Chris@17 69
Chris@17 70 if (in_array('phar', stream_get_wrappers())) {
Chris@17 71 stream_wrapper_unregister('phar');
Chris@17 72 stream_wrapper_register('phar', 'TYPO3\\PharStreamWrapper\\PharStreamWrapper');
Chris@17 73 }
Chris@17 74 ```
Chris@17 75
Chris@17 76 * `PharStreamWrapper` defined as class reference will be instantiated each time
Chris@17 77 `phar://` streams shall be processed.
Chris@17 78 * `Manager` as singleton pattern being called by `PharStreamWrapper` instances
Chris@17 79 in order to retrieve individual behavior and settings.
Chris@17 80 * `Behavior` holds reference to interceptor(s) that shall assert correct/allowed
Chris@17 81 invocation of a given `$path` for a given `$command`. Interceptors implement
Chris@17 82 the interface `Assertable`. Interceptors can act individually on following
Chris@17 83 commands or handle all of them in case not defined specifically:
Chris@17 84 + `COMMAND_DIR_OPENDIR`
Chris@17 85 + `COMMAND_MKDIR`
Chris@17 86 + `COMMAND_RENAME`
Chris@17 87 + `COMMAND_RMDIR`
Chris@17 88 + `COMMAND_STEAM_METADATA`
Chris@17 89 + `COMMAND_STREAM_OPEN`
Chris@17 90 + `COMMAND_UNLINK`
Chris@17 91 + `COMMAND_URL_STAT`
Chris@17 92
Chris@17 93 ## Interceptor
Chris@17 94
Chris@17 95 The following interceptor is shipped with the package and ready to use in order
Chris@17 96 to block any Phar invocation of files not having a `.phar` suffix. Besides that
Chris@17 97 individual interceptors are possible of course.
Chris@17 98
Chris@17 99 ```
Chris@17 100 class PharExtensionInterceptor implements Assertable
Chris@17 101 {
Chris@17 102 /**
Chris@17 103 * Determines whether the base file name has a ".phar" suffix.
Chris@17 104 *
Chris@17 105 * @param string $path
Chris@17 106 * @param string $command
Chris@17 107 * @return bool
Chris@17 108 * @throws Exception
Chris@17 109 */
Chris@17 110 public function assert($path, $command)
Chris@17 111 {
Chris@17 112 if ($this->baseFileContainsPharExtension($path)) {
Chris@17 113 return true;
Chris@17 114 }
Chris@17 115 throw new Exception(
Chris@17 116 sprintf(
Chris@17 117 'Unexpected file extension in "%s"',
Chris@17 118 $path
Chris@17 119 ),
Chris@17 120 1535198703
Chris@17 121 );
Chris@17 122 }
Chris@17 123
Chris@17 124 /**
Chris@17 125 * @param string $path
Chris@17 126 * @return bool
Chris@17 127 */
Chris@17 128 private function baseFileContainsPharExtension($path)
Chris@17 129 {
Chris@17 130 $baseFile = Helper::determineBaseFile($path);
Chris@17 131 if ($baseFile === null) {
Chris@17 132 return false;
Chris@17 133 }
Chris@17 134 $fileExtension = pathinfo($baseFile, PATHINFO_EXTENSION);
Chris@17 135 return strtolower($fileExtension) === 'phar';
Chris@17 136 }
Chris@17 137 }
Chris@17 138 ```
Chris@17 139
Chris@17 140 ## Helper
Chris@17 141
Chris@17 142 * `Helper::determineBaseFile(string $path)`: Determines base file that can be
Chris@17 143 accessed using the regular file system. For instance the following path
Chris@17 144 `phar:///home/user/bundle.phar/content.txt` would be resolved to
Chris@17 145 `/home/user/bundle.phar`.
Chris@17 146 * `Helper::resetOpCache()`: Resets PHP's OPcache if enabled as work-around for
Chris@17 147 issues in `include()` or `require()` calls and OPcache delivering wrong
Chris@17 148 results. More details can be found in PHP's bug tracker, for instance like
Chris@17 149 https://bugs.php.net/bug.php?id=66569
Chris@17 150
Chris@17 151 ## Security Contact
Chris@17 152
Chris@17 153 In case of finding additional security issues in the TYPO3 project or in this
Chris@17 154 `PharStreamWrapper` package in particular, please get in touch with the
Chris@17 155 [TYPO3 Security Team](mailto:security@typo3.org).