Skip to main content

Unverifiable files

Need

Ensuring verifiability of files stored in the repository

Context

  • Usage of Swift for iOS and macOS app development
  • Usage of Foundation for building responsive and mobile-first websites

Description

Non compliant code

import Foundation

func saveFile(fileData: Data, fileName: String, fileExtension: String) {
let documentsUrl: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first as URL!
let fileURL = documentsUrl.appendingPathComponent("\\(fileName).\\(fileExtension)")
do {
try fileData.write(to: fileURL)
} catch {
print("Error saving file: \\(error)")
}
}

This Swift function saveFile takes three parameters: fileData (the content of the file), fileName (the name of the file), and fileExtension (the extension of the file). The function first constructs a URL for the location where the file will be saved (documentsUrl). It then attempts to write the fileData to the file at the constructed URL (fileURL).

The vulnerability here is that the function does not verify if the fileData is compatible with the fileExtension. This means, for example, that you could potentially save a .jpeg image with a .txt extension, which would cause the file to be unopenable or unreadable. This is a problem because it can lead to data corruption, and it can also be exploited by attackers to hide malicious code in files with innocent-looking extensions.

Steps

  • Validate the file extension before saving the file.
  • Use a whitelist approach to only allow specific file extensions that are known to be safe.
  • Implement a file signature verification mechanism to ensure the integrity of the file content.
  • Consider using a secure file storage mechanism that provides built-in file verification and encryption.
  • Regularly update and review the list of allowed file extensions to ensure it remains up-to-date and secure.

Compliant code

import Foundation

// List of allowed file extensions
let allowedFileExtensions = ["jpg", "png", "txt", "pdf"]

func saveFile(fileData: Data, fileName: String, fileExtension: String) {
// Validate the file extension
guard allowedFileExtensions.contains(fileExtension) else {
print("Error: Invalid file extension")
return
}

let documentsUrl: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first as URL!
let fileURL = documentsUrl.appendingPathComponent("\\(fileName).\\(fileExtension)")

do {
// Implement a file signature verification mechanism
let fileSignature = try NSFileHandle(forReadingFrom: fileURL).availableData
if fileSignature != fileData {
print("Error: File signature does not match")
return
}

try fileData.write(to: fileURL)
} catch {
print("Error saving file: \\(error)")
}
}

The updated code includes a validation mechanism for the file extension. It uses a whitelist approach, where only specific file extensions that are known to be safe are allowed. This is done by checking if the provided file extension is in the allowedFileExtensions array.

In addition, a file signature verification mechanism is implemented. This is done by reading the file data from the file URL and comparing it with the provided file data. If the file signatures do not match, an error message is printed and the function returns without saving the file.

This approach ensures that only files with verified content and safe extensions are saved, thus mitigating the risk of storing unverifiable files. It is also recommended to regularly update and review the list of allowed file extensions to ensure it remains up-to-date and secure.

References