Skip to content
This repository was archived by the owner on Jan 31, 2020. It is now read-only.

Commit 643e8a6

Browse files
committed
Merge pull request #37 from MatthiasKuehneEllerhold/unserialize-whitelist
Unserialize whitelist
2 parents 8e43a63 + 4423d9c commit 643e8a6

File tree

4 files changed

+170
-5
lines changed

4 files changed

+170
-5
lines changed

docs/book/adapter.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@ The `Zend\Serializer\Adapter\PhpSerialize` adapter uses the built-in
1616
[serialize()](http://php.net/serialize)/[unserialize()](http://php.net/unserialize)
1717
functions, and is a good default adapter choice.
1818

19-
There are no configurable options for this adapter.
19+
Available options include:
20+
21+
Option | Data Type | Default Value | Description
22+
--------------------------- | ----------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------
23+
unserialize_class_whitelist | `array` or `bool` | `true` | The allowed classes for unserialize(), see [unserialize()](http://php.net/unserialize) for more information. Only available on PHP 7.0 or higher.
24+
2025

2126
## The IgBinary Adapter
2227

src/Adapter/PhpSerialize.php

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
* Zend Framework (http://framework.zend.com/)
44
*
55
* @link http://github.com/zendframework/zf2 for the canonical source repository
6-
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
6+
* @copyright Copyright (c) 2005-2018 Zend Technologies USA Inc. (http://www.zend.com)
77
* @license http://framework.zend.com/license/new-bsd New BSD License
88
*/
99

1010
namespace Zend\Serializer\Adapter;
1111

12+
use Traversable;
1213
use Zend\Serializer\Exception;
1314
use Zend\Stdlib\ErrorHandler;
1415

@@ -21,8 +22,15 @@ class PhpSerialize extends AbstractAdapter
2122
*/
2223
private static $serializedFalse = null;
2324

25+
/**
26+
* @var PhpSerializeOptions
27+
*/
28+
protected $options;
29+
2430
/**
2531
* Constructor
32+
*
33+
* @param array|Traversable|PhpSerializeOptions|null $options
2634
*/
2735
public function __construct($options = null)
2836
{
@@ -35,6 +43,36 @@ public function __construct($options = null)
3543
parent::__construct($options);
3644
}
3745

46+
/**
47+
* Set options
48+
*
49+
* @param array|Traversable|PhpSerializeOptions $options
50+
* @return PhpSerialize
51+
*/
52+
public function setOptions($options)
53+
{
54+
if (! $options instanceof PhpSerializeOptions) {
55+
$options = new PhpSerializeOptions($options);
56+
}
57+
58+
$this->options = $options;
59+
return $this;
60+
}
61+
62+
/**
63+
* Get options
64+
*
65+
* @return PhpSerializeOptions
66+
*/
67+
public function getOptions()
68+
{
69+
if ($this->options === null) {
70+
$this->options = new PhpSerializeOptions();
71+
}
72+
73+
return $this->options;
74+
}
75+
3876
/**
3977
* Serialize using serialize()
4078
*
@@ -85,7 +123,14 @@ public function unserialize($serialized)
85123
}
86124

87125
ErrorHandler::start(E_NOTICE);
88-
$ret = unserialize($serialized);
126+
127+
if (PHP_MAJOR_VERSION >= 7) {
128+
// the second parameter is only available on PHP 7.0 or higher
129+
$ret = unserialize($serialized, ['allowed_classes' => $this->getOptions()->getUnserializeClassWhitelist()]);
130+
} else {
131+
$ret = unserialize($serialized);
132+
}
133+
89134
$err = ErrorHandler::stop();
90135
if ($ret === false) {
91136
throw new Exception\RuntimeException('Unserialization failed', 0, $err);
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
/**
3+
* Zend Framework (http://framework.zend.com/)
4+
*
5+
* @link http://github.com/zendframework/zf2 for the canonical source repository
6+
* @copyright Copyright (c) 2005-2018 Zend Technologies USA Inc. (http://www.zend.com)
7+
* @license http://framework.zend.com/license/new-bsd New BSD License
8+
*/
9+
10+
namespace Zend\Serializer\Adapter;
11+
12+
use Zend\Json\Json as ZendJson;
13+
use Zend\Serializer\Exception;
14+
15+
class PhpSerializeOptions extends AdapterOptions
16+
{
17+
/**
18+
* The list of allowed classes for unserialization (PHP 7.0+)
19+
* Possible values:
20+
* Array of class names that are allowed to be unserialized
21+
* or true if all classes should be allowed (behavior of pre PHP 7.0)
22+
* or false if no classes should be allowed
23+
*
24+
* @var string[]|bool
25+
*/
26+
protected $unserializeClassWhitelist = true;
27+
28+
/**
29+
* @param string[]|bool $unserializeClassWhitelist
30+
*
31+
* @return PhpSerializeOptions
32+
*/
33+
public function setUnserializeClassWhitelist($unserializeClassWhitelist)
34+
{
35+
if (($unserializeClassWhitelist !== true) && (PHP_MAJOR_VERSION < 7)) {
36+
throw new Exception\InvalidArgumentException(
37+
'Class whitelist for unserialize() is only available on PHP 7.0 or higher.'
38+
);
39+
}
40+
41+
$this->unserializeClassWhitelist = $unserializeClassWhitelist;
42+
return $this;
43+
}
44+
45+
/**
46+
* @return string[]|bool
47+
*/
48+
public function getUnserializeClassWhitelist()
49+
{
50+
return $this->unserializeClassWhitelist;
51+
}
52+
}

test/Adapter/PhpSerializeTest.php

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@
1111

1212
use PHPUnit\Framework\TestCase;
1313
use Zend\Serializer;
14+
use Zend\Serializer\Exception\InvalidArgumentException;
1415

1516
/**
16-
* @group Zend_Serializer
17-
* @covers Zend\Serializer\Adapter\PhpSerialize
17+
* @group Zend_Serializer
18+
* @covers \Zend\Serializer\Adapter\PhpSerialize
1819
*/
1920
class PhpSerializeTest extends TestCase
2021
{
@@ -165,4 +166,66 @@ public function testUnserializingInvalidStringRaisesException($string, $expected
165166
$this->expectExceptionMessage($expected);
166167
$this->adapter->unserialize($string);
167168
}
169+
170+
public function testUnserializeNoWhitelistedClasses()
171+
{
172+
$value = 'O:8:"stdClass":0:{}';
173+
174+
if (PHP_MAJOR_VERSION >= 7) {
175+
$this->adapter->getOptions()->setUnserializeClassWhitelist(false);
176+
177+
$data = $this->adapter->unserialize($value);
178+
179+
$this->assertNotInstanceOf(\stdClass::class, $data);
180+
$this->assertInstanceOf('__PHP_Incomplete_Class', $data);
181+
} else {
182+
// In PHP < 7.0 the options-class will throw an exception
183+
184+
self::expectException(InvalidArgumentException::class);
185+
self::expectExceptionMessage('Class whitelist for unserialize() is only available on PHP 7.0 or higher.');
186+
187+
$this->adapter->getOptions()->setUnserializeClassWhitelist(false);
188+
}
189+
}
190+
191+
public function testUnserializeClassNotAllowed()
192+
{
193+
$value = 'O:8:"stdClass":0:{}';
194+
195+
if (PHP_MAJOR_VERSION >= 7) {
196+
$this->adapter->getOptions()->setUnserializeClassWhitelist([\My\Dummy::class]);
197+
198+
$data = $this->adapter->unserialize($value);
199+
200+
$this->assertNotInstanceOf(\stdClass::class, $data);
201+
$this->assertInstanceOf('__PHP_Incomplete_Class', $data);
202+
} else {
203+
// In PHP < 7.0 the options-class will throw an exception
204+
205+
self::expectException(InvalidArgumentException::class);
206+
self::expectExceptionMessage('Class whitelist for unserialize() is only available on PHP 7.0 or higher.');
207+
208+
$this->adapter->getOptions()->setUnserializeClassWhitelist(false);
209+
}
210+
}
211+
212+
public function testUnserializeClassAllowed()
213+
{
214+
$value = 'O:8:"stdClass":0:{}';
215+
216+
if (PHP_MAJOR_VERSION >= 7) {
217+
$this->adapter->getOptions()->setUnserializeClassWhitelist([\stdClass::class]);
218+
219+
$data = $this->adapter->unserialize($value);
220+
$this->assertInstanceOf(\stdClass::class, $data);
221+
$this->assertNotInstanceOf('__PHP_Incomplete_Class', $data);
222+
} else {
223+
// In PHP < 7.0 the options-class will throw an exception
224+
225+
self::expectException(InvalidArgumentException::class);
226+
self::expectExceptionMessage('Class whitelist for unserialize() is only available on PHP 7.0 or higher.');
227+
228+
$this->adapter->getOptions()->setUnserializeClassWhitelist(false);
229+
}
230+
}
168231
}

0 commit comments

Comments
 (0)