Asegurando los datos de iOS en reposo protegiendo los datos del usuario

Este es el primero de los tres artículos sobre la seguridad de los datos de usuario en reposo. En esta publicación, comenzaremos con los aspectos básicos de la protección de datos en iOS para que pueda conocer las mejores prácticas actuales para almacenar datos de forma segura con Swift.

Cualquier aplicación que guarde los datos del usuario debe cuidar la seguridad y privacidad de esos datos. Como hemos visto con las recientes violaciones de datos, puede haber consecuencias muy serias por no proteger los datos almacenados de sus usuarios. En este tutorial, aprenderá algunas de las mejores prácticas para proteger los datos de sus usuarios..

Permisos

Antes de comenzar a almacenar sus datos personalizados, echemos un vistazo a los datos que pueden compartir las aplicaciones del sistema.. 

Para muchas versiones de iOS, se ha requerido que solicite permisos de la aplicación para usar y almacenar algunos de los datos privados del usuario que son externos a la aplicación, como al guardar y cargar imágenes en la biblioteca de fotos. A partir de iOS 10, cualquier API que acceda a los datos privados del usuario requiere que declare ese acceso con anticipación en los proyectos de su proyecto. info.plist expediente. 

Hay muchos marcos que pueden acceder a datos fuera de su aplicación, y cada marco tiene una clave de privacidad correspondiente.

  • Compartir Bluetooth: NSBluetoothPeripheralUsageDescription
  • Calendario: NSCalendarsUsageDescription
  • CallKit: Descripción de NSVoIPUsage
  • Cámara: NSCameraUsageDescription
  • Contactos: NSContactosUsuarioDescripción
  • Salud: NSHealthShareUsageDescription, NSHealthUpdateUsageDescription
  • HomeKit: NSHomeKitUsageDescription
  • Ubicación: NSLocationAlwaysUsageDescription, NSLocationUsageDescription, NSLocationWhenInUseUsageDescription
  • Mediateca: NSAppleMusicUsageDescription
  • Micrófono: NSMicrophoneUsageDescription
  • Movimiento: NSMotionUsageDescription
  • Fotos: NSPhotoLibraryUsageDescription
  • Recordatorios: NSRemindersUsageDescription
  • Reconocimiento de voz: NSSpeechRecognitionUsageDescription
  • SiriKit: NSSiriUsageDescription
  • Proveedor de TV: NSVideoSubscriberAccountUsageDescription

Por ejemplo, aquí hay una entrada en info.plist para permitir que su aplicación cargue y almacene valores en el calendario.

NSCalendarsUsageDescription Ver y agregar eventos a tu calendario.

Si falta una descripción de uso cuando la API intenta acceder a los datos, la aplicación simplemente se bloqueará.

La API de protección de datos

Para cualquier información de usuario que sea interna a la aplicación, lo primero que debe pensar es si necesita almacenar la información y qué datos son esenciales para la aplicación. Mantenga la mayor cantidad de datos esenciales en la memoria de trabajo en lugar de en el almacenamiento de archivos. Esto es especialmente importante para cualquier información de identificación personal.. 

Pero, si debe almacenar datos, es una buena idea habilitar la Protección de datos de Apple.

La protección de datos encripta el contenido del contenedor de su aplicación. Depende de que el usuario tenga un código de acceso y, por lo tanto, la seguridad del cifrado está ligada a la fuerza del código de acceso. Con Touch ID y el cifrado del sistema de archivos actualizado introducido en iOS 10.3, el sistema de protección de datos ha tenido muchas mejoras. Puede activar la protección de datos en su aplicación activando Protección de Datos en el Capacidades sección de su archivo de proyecto. Esto actualiza su perfil de aprovisionamiento y el archivo de derechos para incluir la capacidad de protección de datos. La protección de datos ofrece cuatro niveles de protección, representados por el FileProtectionType estructura:

  • ninguna: sin protección.
  • completar: no se puede acceder a los datos mientras el dispositivo está bloqueado. Esta es la configuración recomendada para la mayoría de las aplicaciones.
  • completeUnlessOpen: se puede acceder a los datos cuando el dispositivo está desbloqueado y sigue estando disponible hasta que se cierre el archivo, incluso si el usuario bloquea el dispositivo. Los archivos también se pueden crear cuando el dispositivo está bloqueado. Esta opción es buena para cuando necesita abrir un archivo para procesar y hacer que el proceso continúe, incluso si el usuario coloca la aplicación en segundo plano y bloquea el dispositivo. Un ejemplo podría ser un trabajo que carga un archivo a un servidor.
  • completeUntilFirstUserAuthentication: cuando se inicia el dispositivo, no se puede acceder a los archivos hasta que el usuario desbloquee el dispositivo por primera vez. Después de eso, los archivos estarán disponibles incluso cuando el dispositivo se vuelva a bloquear. La opción es buena para los archivos a los que se debe acceder en algún momento más adelante en segundo plano cuando el dispositivo está bloqueado, como durante un trabajo de recuperación en segundo plano.

completar es el nivel por defecto. Para ayudar a evitar bloqueos cuando su código intenta acceder a datos que están bloqueados, puede registrarse para recibir notificaciones a través de UIApplicationProtectedDataDidBecomeAvailable y UIApplicationProtectedDataWillBecomeUnavailable para saber cuándo están disponibles los datos.

NotificationCenter.default.addObserver (forName: .UIApplicationProtectedDataDidBecomeAvailable, objeto: nil, cola: OperationQueue.main, usando: (notification) en // ...) NotificationCenter. OperationQueue.main, utilizando: (notificación) en // ...)

Además, también puede consultar la UIApplication.shared.isProtectedDataAvailable bandera.

Una cosa importante a tener en cuenta al habilitar la protección de datos es que si está utilizando algún servicio en segundo plano, como la obtención en segundo plano, es posible que ese código necesite acceso a sus datos en segundo plano cuando el dispositivo está bloqueado. Para esos archivos, deberá establecer un nivel de protección de completeUntilFirstUserAuthentication. Puede controlar el nivel de protección de cada archivo individualmente al crear archivos y directorios utilizando el Administrador de archivos clase.

let ok = FileManager.default.createFile (atPath: somePath, contents: nil, atributos: [FileAttributeKey.protectionKey.rawValue: FileProtectionType.complete]) intente File FileManager.default.createDirectory (atPath: somePath, withIntermediateinter) [FileAttributeKey.protectionKey.rawValue: FileProtectionType.complete]) catch print (error)

También puede establecer el nivel de protección cuando escribe en un archivo. los Datos El objeto tiene un método que puede escribir sus datos en un archivo y puede establecer el nivel de protección cuando llama a este método..

let data = Data.init () let fileURL = try! FileManager.default.url (para: .documentDirectory, en: .userDomainMask, apropiado For: nil, create: false) .appendingPathComponent ("somedata.dat") do try data.write (to: fileURL, options: ([.atomic , .completeFileProtection])) catch print (error)

También puede establecer el nivel de protección al configurar su modelo de Datos Core.

deje que storeURL = docURL? .appendingPathComponent ("Model.sqlite") deje que storeOptions: [AnyHashable: Any] = [NSPersistentStoreFileProtectionKey: FileProtectionType.comnppl. : storeOptions) catch print (error)

Para cambiar el nivel de protección de un archivo existente, use lo siguiente:

do prueba FileManager.default.setAttributes ([FileAttributeKey.protectionKey: FileProtectionType.complete], ofItemAtPath: path) catch print (error)

Integridad de los datos

Parte de proteger sus datos almacenados incluye verificar su integridad. Es una buena práctica no confiar ciegamente en los datos que está cargando desde el almacenamiento; Puede haber sido alterado accidental o maliciosamente. los NSSecureCoding El protocolo se puede utilizar para cargar y guardar de forma segura sus objetos de datos del almacenamiento. Se asegurará de que los objetos que cargue contengan los datos esperados. Si va a guardar su propio objeto, puede cumplir con el protocolo de codificación seguro dentro de su clase.

clase ArchiveExample: NSObject, NSSecureCoding var stringExample: String?… 

La clase debe ser heredada de NSObject. Luego, para activar la codificación segura, anule la Apoya la codificación segura método de protocolo.

estática var admite la codificación de seguridad: Bool obtener devolver verdadero

Si su objeto personalizado se deserializa con init? (codificador aDecoder: NSCoder), la decodeObject (forKey :) método debe ser reemplazado con decodeObject (of: forKey :), lo que garantiza que los tipos de objetos correctos se descompriman del almacenamiento.

required init? (coder aDecoder: NSCoder) stringExample = aDecoder.decodeObject (of: NSString.self, forKey: "string_example") como String?  codificación de función (con aCoder: NSCoder) aCoder.encode (stringExample, forKey: "string_example")

Si estas usando NSKeyedUnarchiver para cargar datos desde el almacenamiento, asegúrese de configurar su requiereSecureCoding propiedad.

class func loadFromSavedData () -> ArchiveExample? var object: ArchiveExample? = nil let path = NSSearchPathForDirectoriesInDomains (.documentDirectory, .userDomainMask, true) [0] como String let url = NSURL (fileURLWithPath: path) en el archivo. : (fileURL? .path)!) do let data = try Data.init (contentsOf: fileURL!) let unarchiver = NSKeyedUnarchiver.init (forReadingWith: data) unarchiver.requiresSecureCoding = true object = unarchiver.decodeObject (of: ArchiveExample .self, forKey: NSKeyedArchiveRootObjectKey) unarchiver.finishDecoding () catch print (error) devuelve el objeto; 

Activar la codificación segura para sus operaciones de guardado evitará que archive accidentalmente un objeto que no se adhiere al protocolo de codificación segura.

func save () let path = NSSearchPathForDirectoriesInDomains (.documentDirectory, .userDomainMask, true) [0] como String let url = NSURL (fileURLWithPath: path) let filePath = url.appendingPathComponent ("ArchiveExample.plist"). = NSMutableData.init () let archiver = NSKeyedArchiver.init (forWritingWith: data) archiver.requiresSecureCoding = true archiver.encode (self, forKey: NSKeyedArchiveRootObjectKey) archiver.finishEncoding () ] do try data.write (toFile: filePath!, options: options) catch print (error)

Más allá NSSecureCoding, siempre es bueno implementar sus propias verificaciones de validación de datos al desempaquetar un archivo o recibir cualquier entrada arbitraria en general.

Senderos de datos

A medida que iOS continúa evolucionando, siempre hay nuevas características que tienen el potencial de filtrar datos almacenados. A partir de iOS 9, puede tener su contenido indexado en la búsqueda de Spotlight, y en iOS 10 puede exponer su contenido a Widgets como el Widget de hoy que aparece en la pantalla de bloqueo. Tenga cuidado si desea exponer su contenido con estas nuevas funciones. Podría terminar compartiendo más de lo que planeaba.!

iOS 10 también agrega una nueva función de transferencia en la que los datos de la mesa de trabajo copiada se comparten automáticamente entre los dispositivos. Nuevamente, tenga cuidado de no exponer datos confidenciales en la mesa de trabajo al traspaso. Puedes hacer esto marcando el contenido sensible como solo locales. También puede establecer una fecha y hora de caducidad para los datos.

let stringToCopy = "copiarme a pasteboard" let pasteboard = UIPasteboard.general if #available (iOS 10, *) let tomorrow = Date (). addingTimeInterval (60 * 60 * 24) pasteboard.setItems ([[[kUTTypeUTF8PlainText as String: stringToCopy]], opciones: [UIPasteboardOption.localOnly: true, UIPasteboardOption.expirationDate: tomorrow]) else pasteboard.string = stringToCopy

Los archivos que se guardan en el almacenamiento del dispositivo pueden ser respaldados automáticamente, ya sea en iTunes o en iCloud. Aunque las copias de seguridad se pueden cifrar, es una buena idea excluir los archivos confidenciales que ni siquiera necesitan salir del dispositivo. Esto se puede hacer configurando el isExcludedFromBackup bandera en el archivo.

let path: String =… var url = URL (fileURLWithPath: path) do var resourceValues ​​= URLResourceValues ​​() // o si desea verificar primero el indicador: // var resourceValues ​​= intente url.resourceValues ​​(forKeys: [.isExcludedFromBackupKey ]) resourceValues.isExcludedFromBackup = true; intente url.setResourceValues ​​(resourceValues) catch print (error)

La animación que ocurre cuando se pone una aplicación en segundo plano se logra cuando iOS toma una captura de pantalla de la aplicación que luego utiliza para la animación. Cuando miras la lista de aplicaciones abiertas en el selector de aplicaciones, esta captura de pantalla también se usa allí. La captura de pantalla se guarda en el dispositivo.. 

Es una buena idea ocultar las vistas que revelen datos confidenciales para que los datos no se capturen en la captura de pantalla. Para hacer esto, configure una notificación cuando la aplicación vaya al fondo y configure la propiedad oculta para los elementos de la IU que desea excluir. Se ocultarán antes de que iOS capture la pantalla. Luego, al llegar al primer plano, puede mostrar los elementos de la interfaz de usuario..

NotificationCenter.default.addObserver (self, selector: #selector (didEnterBackground), nombre: .UIApplicationDidEnterBackground, object: nil) NotificationCenter.default.addObspowerationPliv.

Elimina tus notificaciones cuando la vista desaparezca..

NotificationCenter.default.removeObserver (self, name: .UIApplicationDidEnterBackground, object: nil) NotificationCenter.default.removeObserver (self, name: .UIApplicationWillEnterForeground, object: nil)

Su aplicación también tiene un caché de teclado para los campos de texto que tienen habilitada la corrección automática. El texto que escribe el usuario, junto con las palabras recién aprendidas, se almacenan en la memoria caché para que sea posible recuperar varias palabras que el usuario haya ingresado previamente en su aplicación. La única forma de deshabilitar el caché del teclado es desactivar la opción de autocorrección.

textField.autocorrectionType = UITextAutocorrectionType.no

Debe marcar los campos de contraseña como entrada de texto segura. Los campos de texto seguros no muestran la contraseña ni utilizan el caché del teclado.

textField.isSecureTextEntry = true

Los registros de depuración se guardan en un archivo y se pueden recuperar para las compilaciones de producción de su aplicación. Incluso cuando esté codificando y depurando su aplicación, asegúrese de no registrar información confidencial como contraseñas y claves en la consola. ¡Puede olvidarse de eliminar esa información de los registros antes de enviar su código a la tienda de aplicaciones! Mientras se realiza la depuración, es más seguro usar un punto de interrupción para ver las variables sensibles.

Las conexiones de red también pueden ser almacenadas en caché. Puede encontrar más información sobre cómo eliminar y desactivar la memoria caché de la red en el artículo Seguridad de las comunicaciones en iOS.

Destruyendo datos

Es posible que ya sepa que cuando se elimina un archivo en una computadora, a menudo el archivo en sí no se elimina; sólo se elimina la referencia para el archivo. Para eliminar realmente el archivo, puede sobrescribir el archivo con datos aleatorios antes de eliminarlo. 

El cambio a unidades de estado sólido ha hecho difícil garantizar que los datos hayan sido destruidos, y la mejor forma de eliminarlos de forma segura es el debate. Sin embargo, este tutorial no estaría completo sin un ejemplo de cómo borrar datos del almacenamiento. Debido a algunos otros debates sobre el optimizador Swift, y porque esperamos garantizar que cada byte del archivo se sobrescriba, estamos implementando esta función en C. 

La implementación a continuación puede ir dentro de un archivo .c. Necesitará agregar la definición de la función o el archivo que contiene la función en su encabezado puente para poder usar la función de Swift. Es posible que desee llamar a esta función justo antes de los lugares donde usa Administrador de archivoses Remover archivo metodos Quizás desee implementar las mejores prácticas descritas en este y en los próximos tutoriales sobre una actualización de la aplicación. A continuación, puede borrar los datos no protegidos anteriores durante la migración.

#importar  #importar  #importar  #importar  #importar  #importar  # define MY_MIN (a, b) (((a) < (b)) ? (a) : (b)) int SecureWipeFile(const char *filePath)  int lastStatus = -1; for (int pass = 1; pass < 4; pass++)  //setup local vars int fileHandleInt = open(filePath, O_RDWR); struct stat stats; unsigned char charBuffer[1024]; //if can open file if (fileHandleInt >= 0) // obtener descriptores de archivo int resultado = fstat (fileHandleInt, & stats); if (result == 0) switch (pass) // La implementación del DOD 5220.22-M declara que escribimos sobre tres pases primero con 10101010, 01010101 y luego el tercero con caso de datos aleatorios 1: // sobrescribamos con 10101010 memset (charBuffer, 0x55, sizeof (charBuffer)); descanso; caso 2: // sobrescribir con 01010101 memset (charBuffer, 0xAA, sizeof (charBuffer)); descanso; caso 3: // sobrescribir con arc4random para (sin signo largo i = 0; i < sizeof(charBuffer); ++i)  charBuffer[i] = arc4random() % 255;  break; default: //at least write over with random data for (unsigned long i = 0; i < sizeof(charBuffer); ++i)  charBuffer[i] = arc4random() % 255;  break;  //get file size in bytes off_t fileSizeInBytes = stats.st_size; //rewrite every byte of the file ssize_t numberOfBytesWritten; for ( ; fileSizeInBytes; fileSizeInBytes -= numberOfBytesWritten)  //write bytes from the buffer into the file numberOfBytesWritten = write(fileHandleInt, charBuffer, MY_MIN((size_t)fileSizeInBytes, sizeof(charBuffer)));  //close the file lastStatus = close(fileHandleInt);    return lastStatus; 

Conclusión

En este artículo, ha aprendido cómo configurar permisos para los datos a los que tiene acceso su aplicación, así como sobre cómo garantizar la integridad y protección básica de los archivos. También observamos algunas formas en que los datos de los usuarios se podrían filtrar accidentalmente desde su aplicación. Sus usuarios confían en usted para proteger sus datos. Seguir estas mejores prácticas lo ayudará a pagar esa confianza.

Mientras esté aquí, eche un vistazo a algunas de nuestras otras publicaciones sobre el desarrollo de aplicaciones de iOS!