Re: Built-in classes that cannot be serialized
| From: | Nikita Popov | Date: | Mon, 26 Nov 2018 23:00:47 +0000 |
| Subject: | Re: Built-in classes that cannot be serialized | ||
| References: | 1 2 3 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-103515@lists.php.net to get a copy of this message | ||
On Mon, Nov 26, 2018 at 11:47 PM Stanislav Malyshev <smalyshev@gmail.com>
wrote:
> Hi!
>
> > We should migrate such cases to serialize_deny though. I think it's
> pretty
> > weird to explicitly implement __wakeup (signalling that yes, you can be
> > unserialized), and then use it to throw (sorry, I lied).
>
> Throwing in __wakeup does not signal that it can be serialized. What it
> says that if you try to unserialize it (note that the code doing
> unserialize is not the same that does serialize and has no control over
> what the argument string says - it may demand to unserialize anything)
> it won't work. That _implies_ you shouldn't also serialize it (because
> what's the point) but the important part is not to produce broken
> objects from unserialization loop.
>
> Also, for CURLFile for example there are additional things that happen
> on __wakeup besides throwing, probably for security reasons. I am not
> sure whether they are necessary anymore as we pretty much tell people
> "don't unserialize external data" but they are there for now. Just
> moving to _deny handler would probably not keep them.
>
Historically, __wakeup() has been the correct way to prevent
unserialization and/or mitigate issues relating to dangerous unserialized
state. The reason is that it was possible to bypass the unserialize_deny
handler by using the O-style, rather than the C-style serialization format.
At some point this whole was plugged and we don't allow O-unserializing
classes that have serialize/unserialize handlers.
Which is why nowadays, (un)serialize_deny is our strongest defense against
unserialization vulnerabilities, because it prevents unserialization
*before* the object is constructed. In the __wakeup case the object is
created first and __wakeup is only called much later at the end of
unserialization, which creates a lot more opportunities for the usual
shenanigans.
Basically, anything using a throwing __wakeup() nowadays is a leftover from
times where unserialize_deny was not properly enforced. To the best of my
knowledge, there is no good reason to use the throwing __wakeup pattern
nowadays anymore.
Regards,
Nikita