logo

Insecure deserialization - Php


Need

Secure deserialization process


Context

  1. Usage of PHP for server-side scripting and web development
  2. Usage of PHP for server-side scripting and web development

Description

Insecure Code Example

<?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

  1. First, avoid using PHP's unserialize() function on untrusted data. This function can lead to code execution, SQL injection, and other serious vulnerabilities.
  2. Instead of unserialize(), consider using json_decode() or other safer methods for deserialization.
  3. 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.
  4. Always validate and sanitize input data. In this case, ensure that the 'data' parameter is of the expected format and type before deserializing it.
  5. 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.
  6. Consider using encryption for serialized data. This can prevent an attacker from tampering with the serialized data to inject malicious objects.

Secure Code Example

<?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

  • 096 - Insecure deserialization

  • Last updated

    2023/09/18