I'm writing a this email to propose adding allowed_classes_callback option to 
unserialize(). 

The class name as parsed from the serialized string is passed as a parameter to 
the callback, it should return a boolean. true would allow the class, false 
would block it. This blocks classes the same way 'allowed_classes' would, but 
by callback instead. The callback will be triggered *after* allowed_classes is 
evaluated (if present). Blocking will have the same effect as allowed_classes, 
using __PHP_Incomplete_Class.

This callback would solve a few problems where allowed_classes is not 
sufficient:

- This would also allow for fixing legacy applications where it is not exactly 
clear what is being unserialized. In my use-case the callable returns a true 
value but a E_USER_DEPRECATION is triggered. This way data can be collected 
about what classes to allow through monitoring these deprecations, providing a 
non-disrupting way to secure unserialize calls. This is especially helpful in 
very generic unserialize usages like caches.

- It would allow for an is_subclass_of() check where for example an interface 
can be added to classes that are safe to get unserialized. Current 
allowed_classes array only matches the exact class, not it's children. 

Note that these problems are not resolvable by using unserialize_callback_func 
because that call only happens for unloaded classes, where the PHP Object 
Injection vulnerability 
https://owasp.org/www-community/vulnerabilities/PHP_Object_Injection affects 
classes that might already have been loaded.

In de pull request Jakub wrote:
> Personally I don't see any issue here and it seems quite self contained and 
> small so I wouldn't mind to get it merged without RFC. It might be worth to 
> email internals first to double check that there are no objections first.

Out of scope: I understand that __PHP_Incomplete_Class is not very 2025. Adding 
an option throw_for_unknown_classes has been suggested on this list. I'm happy 
to implement that, but for now I'd like to keep it at allowed_classes_callback.

Feedback is very much appreciated.

The change and some more details live here: 
https://github.com/php/php-src/pull/19087

Reply via email to