9.4 KiB
NSCoding y NSSecureCoding
iOS cuenta con dos protocolos para la serialización de objetos para Objective-C o NSObject
s: NSCoding
y NSSecureCoding
. Cuando una clase se ajusta a cualquiera de los protocolos, los datos se serializan a NSData
: un envoltorio para buffers de bytes. Tenga en cuenta que Data
en Swift es lo mismo que NSData
o su contraparte mutable: NSMutableData
. El protocolo NSCoding
declara los dos métodos que deben implementarse para codificar/decodificar sus variables de instancia. Una clase que utiliza NSCoding
necesita implementar NSObject
o estar anotada como una clase @objc. El protocolo NSCoding
requiere implementar encode e init como se muestra a continuación.
class CustomPoint: NSObject, NSCoding {
//required by NSCoding:
func encode(with aCoder: NSCoder) {
aCoder.encode(x, forKey: "x")
aCoder.encode(name, forKey: "name")
}
var x: Double = 0.0
var name: String = ""
init(x: Double, name: String) {
self.x = x
self.name = name
}
// required by NSCoding: initialize members using a decoder.
required convenience init?(coder aDecoder: NSCoder) {
guard let name = aDecoder.decodeObject(forKey: "name") as? String
else {return nil}
self.init(x:aDecoder.decodeDouble(forKey:"x"),
name:name)
}
//getters/setters/etc.
}
El problema con NSCoding
es que el objeto a menudo ya está construido e insertado antes de que puedas evaluar el tipo de clase. Esto permite a un atacante inyectar fácilmente todo tipo de datos. Por lo tanto, se ha introducido el protocolo NSSecureCoding
. Al conformarse con NSSecureCoding
, es necesario incluir:
static var supportsSecureCoding: Bool {
return true
}
Cuando init(coder:)
es parte de la clase. A continuación, al decodificar el objeto, se debe realizar una comprobación, por ejemplo:
let obj = decoder.decodeObject(of:MyClass.self, forKey: "myKey")
La conformidad con NSSecureCoding
asegura que los objetos que se están instanciando son realmente los que se esperaban. Sin embargo, no se realizan controles adicionales de integridad sobre los datos y los datos no están cifrados. Por lo tanto, cualquier dato secreto necesita cifrado adicional y los datos cuya integridad deba ser protegida, deben tener un HMAC adicional.
Archivado de objetos con NSKeyedArchiver
NSKeyedArchiver
es una subclase concreta de NSCoder
y proporciona una forma de codificar objetos y almacenarlos en un archivo. El NSKeyedUnarchiver
decodifica los datos y recrea los datos originales. Tomemos el ejemplo de la sección NSCoding
y ahora los archivamos y desarchivamos:
// archiving:
NSKeyedArchiver.archiveRootObject(customPoint, toFile: "/path/to/archive")
// unarchiving:
guard let customPoint = NSKeyedUnarchiver.unarchiveObjectWithFile("/path/to/archive") as?
CustomPoint else { return nil }
También puedes guardar la información en el plist primario NSUserDefaults
:
// archiving:
let data = NSKeyedArchiver.archivedDataWithRootObject(customPoint)
NSUserDefaults.standardUserDefaults().setObject(data, forKey: "customPoint")
// unarchiving:
if let data = NSUserDefaults.standardUserDefaults().objectForKey("customPoint") as? NSData {
let customPoint = NSKeyedUnarchiver.unarchiveObjectWithData(data)
}
Codable
Es una combinación de los protocolos Decodable
y Encodable
. Un String
, Int
, Double
, Date
, Data
y URL
son Codable
por naturaleza: lo que significa que pueden ser codificados y decodificados fácilmente sin ningún trabajo adicional. Tomemos el siguiente ejemplo:
struct CustomPointStruct:Codable {
var x: Double
var name: String
}
Al agregar Codable
a la lista de herencia de CustomPointStruct
en el ejemplo, los métodos init(from:)
y encode(to:)
son compatibles automáticamente. Para obtener más detalles sobre el funcionamiento de Codable
, consulte la documentación de desarrolladores de Apple.
También puede usar codable para guardar los datos en la lista de propiedades primarias NSUserDefaults
:
struct CustomPointStruct: Codable {
var point: Double
var name: String
}
var points: [CustomPointStruct] = [
CustomPointStruct(point: 1, name: "test"),
CustomPointStruct(point: 2, name: "test"),
CustomPointStruct(point: 3, name: "test"),
]
UserDefaults.standard.set(try? PropertyListEncoder().encode(points), forKey: "points")
if let data = UserDefaults.standard.value(forKey: "points") as? Data {
let points2 = try? PropertyListDecoder().decode([CustomPointStruct].self, from: data)
}
Codificación JSON
Existen muchas bibliotecas de terceros para codificar datos en JSON (como se explica aquí). Sin embargo, Apple proporciona soporte para la codificación/decodificación de JSON directamente combinando Codable
junto con un JSONEncoder
y un JSONDecoder
:
struct CustomPointStruct: Codable {
var point: Double
var name: String
}
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let test = CustomPointStruct(point: 10, name: "test")
let data = try encoder.encode(test)
let stringData = String(data: data, encoding: .utf8)
// stringData = Optional ({
// "point" : 10,
// "name" : "test"
// })
XML
Existen múltiples formas de codificar XML. Al igual que con el análisis de JSON, existen varias bibliotecas de terceros, como: Fuzi, Ono, AEXML, RaptureXML, SwiftyXMLParser, SWXMLHash
Varían en términos de velocidad, uso de memoria, persistencia de objetos y lo más importante: difieren en cómo manejan las entidades XML externas. Vea XXE en el visor de Office de Apple iOS como ejemplo. Por lo tanto, es clave deshabilitar el análisis de entidades externas XML si es posible. Consulte la hoja de trucos de prevención de XXE de OWASP para obtener más detalles. Además de las bibliotecas, se puede hacer uso de la clase XMLParser
de Apple
Cuando no se utilizan bibliotecas de terceros, sino la clase XMLParser
de Apple, asegúrese de que shouldResolveExternalEntities
devuelva false
.
{% hint style="danger" %}
Todas estas formas de serializar/codificar datos se pueden utilizar para almacenar datos en el sistema de archivos. En esos escenarios, verifique si los datos almacenados contienen algún tipo de información sensible.
Además, en algunos casos puede ser posible abusar de algunos datos serializados (capturándolos a través de MitM o modificándolos dentro del sistema de archivos) deserializando datos arbitrarios y haciendo que la aplicación realice acciones inesperadas (ver la página de deserialización). En estos casos, se recomienda enviar/guardar los datos serializados cifrados y firmados.
{% endhint %}
Referencias
{% embed url="https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06h-testing-platform-interaction#testing-object-persistence-mstg-platform-8" %}
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
-
¿Trabajas en una empresa de ciberseguridad? ¿Quieres ver tu empresa anunciada en HackTricks? o ¿quieres tener acceso a la última versión de PEASS o descargar HackTricks en PDF? ¡Consulta los PLANES DE SUSCRIPCIÓN!
-
Descubre The PEASS Family, nuestra colección de exclusivos NFTs
-
Consigue el oficial PEASS & HackTricks swag
-
Únete al 💬 grupo de Discord o al grupo de telegram o sígueme en Twitter 🐦@carlospolopm.
-
Comparte tus trucos de hacking enviando PRs al repositorio de hacktricks y al repositorio de hacktricks-cloud.