Skip to main content

Insecure deserialization

Need

Secure deserialization process

Context

  • Usage of PHP for server-side scripting and web development
  • Usage of PHP for server-side scripting and web development

Description

Non compliant code

<?php
class User {
public $username;
public $isAdmin;
}

$data = $_GET['data'];
$unserializedData = unserialize($data);

if($unserializedData->isAdmin){
echo 'Welcome, Admin!';
}
?>

The above PHP code is an example of insecure deserialization. The unserialize() function is used to convert a serialized string back into a PHP value. In the context of this code, the serialized string is fetched from the $_GET['data'] parameter.

The problem here is that the unserialize() function is used without any checks or validation on the input data. This means that an attacker could potentially control the input to unserialize(), which could lead to several types of attacks, such as code execution, SQL injection, path traversal, and others.

In this specific case, an attacker could create a serialized object of the User class with the isAdmin property set to true, even if they are not an admin. This would grant them admin access, leading to privilege escalation.

Insecure deserialization can also lead to Denial of Service (DoS) attacks. For example, if an attacker provides a specially crafted string that, when unserialized, consumes a lot of memory or CPU, it could cause the application to slow down or even crash.

Steps

  • First, avoid using PHP's unserialize() function on untrusted data. This function can lead to code execution, SQL injection, and other serious vulnerabilities.
  • Instead of unserialize(), consider using json_decode() or other safer methods for deserialization.
  • If you must use unserialize(), use PHP 7's allowed_classes option to whitelist classes that can be unserialized. This prevents arbitrary code execution by restricting which objects can be created.
  • Always validate and sanitize input data. In this case, ensure that the 'data' parameter is of the expected format and type before deserializing it.
  • Implement proper error handling. If the deserialization fails or an unexpected object type is encountered, the program should handle this gracefully instead of potentially exposing sensitive information or system functionality.
  • Consider using encryption for serialized data. This can prevent an attacker from tampering with the serialized data to inject malicious objects.

Compliant code

<?php
class User {
public $username;
public $isAdmin;
}

$data = $_GET['data'];

// Check if the data is a valid JSON
if (json_decode($data) != null) {
$unserializedData = json_decode($data);
} else {
// Handle error
die("Invalid data format.");
}

if(isset($unserializedData->isAdmin) && $unserializedData->isAdmin){
echo 'Welcome, Admin!';
} else {
echo 'Access Denied.';
}
?>

The updated code now uses json_decode() instead of unserialize(). This is a safer method for deserialization and it doesn't have the same vulnerabilities as unserialize().

Before deserializing the data, we first check if it's a valid JSON string using json_decode(). If it's not, we stop the execution of the script and output an error message. This is a basic form of input validation and error handling.

After deserializing the data, we check if the isAdmin property is set and if it's true. If it is, we output a welcome message. If it's not, we output an access denied message. This is a basic form of access control.

This code is more secure than the original code, but it's still not perfect. For example, it doesn't use encryption for the serialized data, and it doesn't whitelist specific classes that can be unserialized. However, it's a good starting point for improving the security of the application.

References