max_depth
Option
for unserialize()
The unserialize()
function takes a string as its
first argument that contains a single serialized variable and
converts it back into a PHP value. This string is usually generated
using the serialize()
function. It is, of course, a bad
idea, especially from a security point of view, to pass a value
comes from the outside, from $_GET
, for instance, to
unserialize()
.
In the “Secure
unserialize()
” section we already discussed the
allowed_classes
option that limits the creation of
objects through unserialize()
to a list of classes. But
automatic code execution through, for instance, the constructor of a
class through an invocation of unserialize()
with an
unsafe argument is only one possible attack vector.
An attacker could prepare a string that leads to a stack overflow
during the unserialization of deeply nested structures. To deal with
this scenario, the max_depth
option was introduced in
PHP 7.4.
var_dump(
unserialize(
'a:1:{i:0;a:1:{i:0;a:1:{i:0;a:0:{}}}}'
)
);
Executing the code shown above will print the output shown below:
array(1) {
[0]=>
array(1) {
[0]=>
array(1) {
[0]=>
array(0) {
}
}
}
}
The array that is encoded in the string that is passed to
unserialize()
has a depth of 3. Here is an example of
how to limit the depth of structures to be unserialized:
var_dump(
unserialize(
'a:1:{i:0;a:1:{i:0;a:1:{i:0;a:0:{}}}}',
[
'max_depth' => 2
]
)
);
Executing the code shown above will print the output shown below:
Warning: unserialize(): Maximum depth of 2 exceeded. The depth limit can be
changed using the max_depth unserialize() option or the
unserialize_max_depth ini setting in ...
bool(false)
As you can see, PHP emits a warning that
unserialize()
was not successful due to the maximum
depth that is allowed for nested structures. And instead of an array
the function returned false
.
The unserialize_max_depth
configuration option can
be set in your php.ini
configuration file, for
instance, to configure a maximum depth for unserializing nested
structures for all unserialize()
calls.
It should go without saying that you should not pass unsafe
values that come from the outside to a function such as
unserialize()
to begin with.