I need to store structured data in a cookie.
favorites of some catalog page. the data is { {id,type} , {id,type} , ... }
In my code i need to put it back to a an array. so i am using the unserialize() function to recover the data.
Is there a way to prevent object injection? any alternative for the unserialize function?
Is there a way to prevent object injection
When you unserialize an object, PHP will call the __wakeup method in the class' definition (this is not stored in the cookie but in your PHP class file on the server).
Would it be possible for someone to change the serialized object's class and guess correctly causing a __wakeup function to perform some task? Yes. Usually __wakeup functions will simply reconnect to a resource so this may or may not be a big deal but why risk it? Just store the array as JSON with json_encode($yourdata) and get it back with json_decode($cookiedata, true)
As long as the data being stored client-side does not pose a security risk (i.e., reveals sensitive information) it's fine. Storing a user's favorites can be appropriate for this, especially if it's a high traffic site and you don't want to have to perform a database fetch or long sessions for this type of data.
Well, if you have a defined structure of how your array should look, then just make sure that the string you're unserializing is really an array when you're iterating over it just check the value type (id -> int, type -> string).
Plus, I think json_encode will be better in your case of data, it is smaller in size and faster in decoding (and you can work with it on the client-side).
The way I'm thinking about would be to encrypt the cookie information, to prevent the user from knowing what the hell is he/she editing
If you don't want the user to potentially modify the data, then don't give the data to the user in the first place. Use $_SESSION, a database, or write the info to a file on your server.
Related
TLDR: Is it safe to serialize the $_POST array to a file and then read it back into the $_POST variable on a different request or a different script?
I realize this is unusual. There is a reason for it, and it would take a dozen pages of text to explain why I am considering doing it in a special case, at least in the meantime.
Boiled down process:
file_put_contents('sample.post', serialize($_POST));
$_POST = unserialize(file_get_contents('sample.post'));
I already have extensive filtering in place for the actual contents of the post variable. My question is whether or not the process of serializing and unserializing the entire $_POST array is giving a malicious user a method of attack.
The PHP doc says "Warning. Do not pass untrusted user input to unserialize(). Unserialization can result in code being loaded and executed due to object instantiation and autoloading, and a malicious user may be able to exploit this."
I found these articles that describe this method of attack. But they seem to depend on the user being able to specify the string to unserialize directly, IE unserialize($_POST['value']).
https://www.notsosecure.com/remote-code-execution-via-php-unserialize/
https://heine.familiedeelstra.com/security/unserialize
Am I correct that as long as I am serializing and unserializing, objects can't be created in the unserializing process, right?
I am under the impression that the $_POST array will only ever contain strings (though I couldn't find that explicitly mentioned in the PHP docs).
As I understand it, even if someone supplies a string matching the format of a serialized object, it will be 'stored' as a string during serialization, with an explicit length (byte length). So it will just be assigned as a string when unserializing. It seems like since the lengths of the strings are stored along with them during serialization, you can't break the structure of a serialized string from the input like you might with SQL injection. I tried to trick it with some invalid multi-byte characters, but no luck. However, me being unable to do it and experienced hackers being able to do it are 2 different things.
I couldn't find anything else about other attack methods.
Please let me know if I'm missing something! I just read several comments saying 'you should never do this', so I'm nervous that I'm misunderstanding something.
I think it is not possible without further attacks to send something as a POST variable to exploit the unserialize() call later in your scenario, but others may probably have an idea. It could be a problem if $_POST had something unserializable, but I think that may not happen. Whatever was in $_POST, it was already in memory once, so assuming serialize() and unserialize() work correctly, it should be secure to do something like
$serialized = serialize($userinput);
unserialize($serialized);
However, you are saving this data to disk inbetween. After exploiting a different flaw and having access to your files (or having access "by design", like IT ops staff), an attacker may be able to modify saved serialized data, and may inject his attack there. That way it would obviously be vulnerable.
So it is indeed a risk, albeit maybe not a very high one. Be aware that the security of this solution depends a lot on security of your saved serialized content.
I have 8 input type text. name=favour_01
I make those 8 input into an array and serialize it
i use PDO to save it into DB.
Than unserialize it for output
$favour[]='apple'; $favour[]='banana';
$favours = serialize($favours);
prepare(...
$food->bindValue(':favours', $favours, PDO::PARAM_STR);
is this secure? I have read serialize input is vulnerable.
I didn't use any class for this, here is one post i have read https://www.owasp.org/index.php/PHP_Object_Injection
Serializing data is only a security risk when the data you serialize contains sensitive information. The risk is that you serialize data that contains passwords for example and then you store the serialized form somewhere insecure.
Unserializing data is a security risk if you try to unserialize data that you got from an untrusted source. The unserialization process can instantiate objects and the data input may therefore do things you don't anticipate.
What you're doing for serializing a simple array of values to bind it to a SQL parameter is okay from a security point of view, but keep in mind you won't be able to search the database efficiently for specific values within that serialized array. Basically your database becomes a black box: you can stuff a whole array into it, and fetch the whole array out to deserialize it, but you can't easily read or write individual elements of the array with SQL.
It's better practice to create a child table and store one element per row in that table.
yes it is safe if you use prepared statement, then validate data after retrieving it from the database to before output to browser.
I'm passing urlencode()d serialize()d arrays around my webpages, via $_GET[].
Is it safe to deserialize() a value from $_GET? The deserialized array will sometimes be shown to the user. Would it be possible for a user to expose/reference variables or functions etc within my code? In other words, when deserializing the value, does PHP treat it as data or code?
Update:
I see the documentation says:
"Circular references inside the array/object you are serializing will also be stored. Any other reference will be lost. "
So that means i'm safe? :-)
Absolutely, positively, no.
You shouldn't blindly trust anything from the client side, however there is a way you can give yourself more confidence.
I'm assuming that if you've got PHP serialized data coming from the client side, that client obtained that from a server at some point? If that's the case, and the client doesn't modify the data, you could include a hash along with the data to verify it hasn't been tampered with.
The other alternative would be to unserialize the object, but regard it as 'tainted', then copy and re-verify the unserialized data into a 'clean' object.
This method is as "safe "as any other kind of incoming GET or POST data - you will always need to sanitize the data before working with it! But there are additional issues with unserializing user data.
When unserializing an object, PHP will look whether the class has a __wakeup magic method. That method will get executed if present.
Now this is not a massive security hole in itself, because the class definition is never transmitted in the serialized data. Any malicious code would have to be present in the system already. However, there are conceivable scenarios where this could be a problem (e.g. a plug-in system that can install third party code) and I would be very wary with this.
Also, theoretically, this allows an attacker to create an object of any class inside your script. While not a security problem straight away, it is surely not good practice to do.
JSON encoding would be a more safe way, because it can contain only "dumb" data.
You are serializing only data-part of objects/arrays/variables, the actual executable code is not serialized- there is no point in doing that - serialization helps to transfer your data between two different worlds- executed code can be same or different there - for data it does not matter.
Though possible hacks would be possible - but only based on data - classes and types and values might differ - it's up the code how can it cope with errors during deserialization.
Yes, its safe. You are asking is it safe to serialize the value of the $_GET array. Yes, it is safe. Nothing gets executed during the serialization of array. Since $_GET array does not contain any objects, only the parameters from query string, it cannot do any harm during serialization/unserialization.
You mentioned something you saw on documentation about circular references. Don't worry about that, it does not apply in your case because there are no objects inside the $_GET array.
As far as using the actual data from the $_GET array, that's a different question and the answer would be no, it's not safe to use data from the $_GET array without applying some type of filter or validation first
I'm creating a multi-step survey and want to store the data in $_SESSION before writing everything to a database. Is there anything I should be doing to the data before storing it there from a security perspective?
Assuming you're on the regular file-based sessions, then you don't have much to worry about from an injection vulnerability view. PHP will take care of the mechanics of read/writing the session file, using serialize() and the like. Stuff whatever you want into $_SESSION and it'll magically be there on the next page invocation.
However, from the broader security perspective, anything that goes into the session file IS readable by anything else running under the same web server instance (e.g. the apache user ID). So it's not somewhere you could store sensitive data, let along things like credit cart/cvv numbers.
well, to avoid problems recovering the data, i suggest you to use a name for the session and use an array exclusively for the post data, kinda:
$_SESSION['postData'] = $_POST;
Its fairly safe to throw whatever you want in the session without sanitizing it. You could though, since you're going to anyways, sanitize it before putting it in the session so its ready to go into the database, then you can sleep more soundly.
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?
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.