Is there any way to limit PHP's unserialize() to only parse arrays? For security reasons. Suppose there is is an evil __unserialize() magic method in the unserialized object I don't wanna call!
Is there any way to limit PHP's unserialize() to only parse arrays? For security reasons. Suppose there is is an evil __unserialize() magic method in the unserialized object I don't wanna call!
Not that I know of, no.
It is possible to find out the type of a serialized value using a function like this one, but that won't help you either, as any member of the array could again be an object whose unserializing will trigger a __wakeup()
call.
You would have to extend that function so it walks through all the members of the serialized string without actually serializing it. Certainly possible, but potentially kludgy and slow.
The only other way that comes to mind is to make the unserialize()
call in an environment in which no classes are defined. That will result in a broken object of the class __PHP_Incomplete_Class
that you may then be able to parse out. In a normal script environment, this will however not help you.
That said, never forget that a serialized object will never contain any code. The class definition will have to be present in your code base through other means.
In light of that, I'm not sure under what circumstances this can be a security problem in the first place. If you have malicious code in your code base, there will be plenty of chance to execute it without having to unserialize anything, won't they?
I have never seen this attack vector in the wild. If you are expecting to get an array then you won't be calling $obj->method()
on the results thus it will be difficult to influence the application.
However, you can use this simple function:
function safe_unserialize($s){
$a=unserialize($s)
if(is_array($a)){
return $a;
}else{
return false;
}
}
the __constructor()
function might be called, i'm not sure about this and i can't test it right now. This shouldn't be a problem because in the vast majority of cases this is just initializing variables.
There are a couple of ways you could solve this problem:
- Use a regex on the serialized string:
Piwik patched an unserialize vulnerability with the following check:
if (preg_match('/^a:[0-9]+:{/', $str)
&& !preg_match('/(^|;|{|})O:\+?[0-9]+:"/', $str)
Sign the signed string. If you add an sha1 Hash of the serialized string + a secret to the Cookie/POST Var. You can be sure that the serialized string isn't manipulated.
Write your own unserialize function. If you are only interested in Arrays, you don't need unserialize. Write something on your own or use an accepted standard like JSON etc.
And please ignore all comments that don't see a security issue here. unserialize() vulnerabilites exists in an incredible high percentage of PHP5 Applications and most books and tutorials don't even talk about them.