Skip to main content

Insecure deserialization

Need

Secure deserialization process

Context

  • Usage of Swift for iOS and macOS app development
  • Usage of Foundation for building responsive and accessible web interfaces

Description

Non compliant code

import Foundation

// The following code represents an insecure deserialization vulnerability

let data = ... // some NSData instance
let unarchiver = NSKeyedUnarchiver(forReadingWith: data as Data)
let myObject = unarchiver.decodeObject(forKey: "SomeKey")

The above Swift code for iOS shows a case of insecure deserialization vulnerability. Here, an object is being deserialized without validating its content or type, which can be a potential security risk.

The NSKeyedUnarchiver is used to decode a previously serialized object graph. The decodeObject(forKey:) method is then used to decode the root object of the graph. However, there's no validation or type casting performed on the deserialized object.

This means that if an attacker can control the serialized data, they could potentially manipulate the data to cause unintended behavior in the application. This could include executing arbitrary code, creating denial-of-service attacks, or achieving privilege escalation.

To fix this vulnerability, you should always validate and typecast deserialized data.

Steps

  • Validate the deserialized object's content before using it.
  • Cast the deserialized object to a specific type to ensure its integrity.
  • Use a secure deserialization mechanism, such as JSON or XML parsing, instead of NSKeyedUnarchiver.

Compliant code

import Foundation

// Secure deserialization
let data = ... // some NSData instance
let unarchiver = NSKeyedUnarchiver(forReadingWith: data as Data)

// Validate and cast the object
if let myObject = unarchiver.decodeObject(forKey: "SomeKey") as? ExpectedType {
// Use the object
} else {
// Handle the error
}

The original code was vulnerable to insecure deserialization attacks because it did not validate the content of the deserialized object nor cast it to a specific type. This could allow an attacker to inject malicious data into the serialized object, leading to potential code execution, denial of service, or other security issues.

The fixed code mitigates this vulnerability by:

  1. Validating the deserialized object's content: Before using the deserialized object, the code checks if it can be cast to the expected type (ExpectedType in the example). If the object cannot be cast to this type, it means that the object's content is not what was expected, indicating a potential attack. In this case, the code does not use the object and instead handles the error.

  2. Casting the deserialized object to a specific type: By casting the deserialized object to a specific type, the code ensures that the object has the expected structure and values. This prevents an attacker from injecting malicious data into the object that could cause unexpected behavior when the object is used.

  3. Using a secure deserialization mechanism: While the code still uses NSKeyedUnarchiver for deserialization, it is recommended to use a more secure deserialization mechanism, such as JSON or XML parsing, which are less prone to insecure deserialization vulnerabilities.

References