Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. iOS SDK
Code

Asegurar las comunicaciones en iOS

by
Length:LongLanguages:

Spanish (Español) translation by CYC (you can also view the original English article)

La seguridad móvil se ha convertido en un tema candente. Para cualquier aplicación que se comunique de forma remota, es importante considerar la seguridad de la información del usuario que se envía a través de una red. En esta publicación, aprenderás las mejores prácticas actuales para proteger las comunicaciones de tu aplicación iOS en Swift.

Usa HTTPS

Al desarrollar tu aplicación, considera limitar las solicitudes de red a aquellas que son esenciales. Para esas solicitudes, asegúrate de que se realicen a través de HTTPS y no a través de HTTP: esto ayudará a proteger los datos del usuario de los "ataques del hombre en el medio", donde otra computadora en la red actúa como un retransmisor para su conexión, pero recibe o cambia los datos que pasan. La tendencia en los últimos años es tener todas las conexiones hechas a través de HTTPS. Afortunadamente para nosotros, las versiones más nuevas de Xcode ya lo hacen cumplir.

Para crear una solicitud HTTPS simple en iOS, todo lo que tenemos que hacer es agregar "s" a la sección "http" de la URL. Siempre que el host admita HTTPS y tenga certificados válidos, obtendremos una conexión segura. Esto funciona para API como URLSession, NSURLConnection y CFNetwork, así como bibliotecas de terceros populares como AFNetworking.

Seguridad de transporte de la aplicación

Con los años, HTTPS ha tenido varios ataques en su contra. Dado que es importante tener el HTTPS configurado correctamente, Apple ha creado App Transport Security (ATS para abreviar). ATS se asegura de que las conexiones de red de tu aplicación utilicen protocolos estándares de la industria, para que no envíe accidentalmente datos del usuario de forma insegura. La buena noticia es que ATS está habilitado de forma predeterminada para las aplicaciones creadas con las versiones actuales de Xcode.

ATS está disponible a partir de iOS 9 y OS X El Capitan. Las aplicaciones actuales en la tienda de repente no requieren ATS, pero las aplicaciones creadas en las versiones más nuevas de Xcode y sus SDK lo habilitarán de manera predeterminada. Algunas de las mejores prácticas aplicadas por ATS incluyen el uso de TLS versión 1.2 o superior, el secreto hacia adelante mediante el intercambio de claves ECDHE, el cifrado AES-128 y el uso de al menos certificados SHA-2.

Es importante tener en cuenta que, aunque ATS se habilita automáticamente, no necesariamente significa que ATS se aplica en tu aplicación. ATS trabaja en las clases básicas como URLSession y NSURLConnection y las interfaces CFNetwork basadas en secuencias. ATS no se aplica en las interfaces de red de nivel inferior, como sockets sin formato, sockets de CFNetwork o bibliotecas de terceros que utilizarían estas llamadas de bajo nivel. Entonces, si usas redes de bajo nivel, deberás tener cuidado de implementar las mejores prácticas de ATS manualmente.

Excepciones ATS

Dado que ATS impone el uso de HTTPS y otros protocolos seguros, es posible que te preguntes si todavía podrás realizar conexiones de red que no admitan HTTPS, como cuando descargas imágenes de un caché CDN. No te preocupes, puedes controlar la configuración de ATS para dominios específicos en el archivo plist de tu proyecto. En Xcode, encuentra tu archivo info.plist, haz clic derecho sobre él y elige Abrir como > Código fuente.

Encontrarás una sección llamada NSAppTransportSecurity. Si no está allí, puedes agregar el código tu mismo; el formato es el siguiente.

Esto te permite cambiar la configuración de ATS para todas las conexiones de red. Algunas de las configuraciones comunes son las siguientes:

  • NSAllowsArbitraryLoads: Deshabilita ATS. ¡No uses esto! Las versiones futuras de Xcode eliminarán esta clave.
  • NSAllowsArbitraryLoadsForMedia: Permite la carga de medios sin restricciones ATS para el marco de AV Foundation. Solo debe permitir cargas inseguras si sus medios ya están encriptados por otros medios. (Disponible en iOS 10 y macOS 10.12).
  • NSAllowsArbitraryLoadsInWebContent: Se puede usar para desactivar las restricciones ATS de los objetos de vista web en tu aplicación. Piensa primero antes de desactivar esto, ya que permite a los usuarios cargar contenido inseguro arbitrario dentro de tu aplicación. (Disponible en iOS 10 y macOS 10.12).
  • NSAllowsLocalNetworking: Esto se puede usar para permitir que los recursos de la red local se carguen sin restricciones ATS. (Disponible en iOS 10 y macOS 10.12).

El diccionario NSExceptionDomains te permite establecer configuraciones para dominios específicos. Aquí hay una descripción de algunas de las claves útiles que puedes usar para tu dominio:

  • NSExceptionAllowsInsecureHTTPLoads: Permite que el dominio específico use conexiones que no sean HTTPS.
  • NSIncludesSubdomains: Especifica si las reglas actuales se pasan a los subdominios.
  • NSExceptionMinimumTLSVersion: Se utiliza para especificar versiones de TLS antiguas y menos seguras que están permitidas.

Perfect Forward Secrecy

Si bien el tráfico encriptado no se puede leer, aún puede almacenarse. Si la clave privada utilizada para encriptar ese tráfico se ve comprometida en el futuro, la clave se puede usar para leer todo el tráfico previamente almacenado.

Para evitar este tipo de compromiso, Perfect Forward Secrecy (PFS) genera una clave de sesión que es única para cada sesión de comunicación. Si la clave para una sesión específica se ve comprometida, no comprometerá los datos de ninguna otra sesión. ATS implementa PFS por defecto, y puedes controlar esta característica usando la clave plist NSExceptionRequiresForwardSecrecy. Al apagar esto, se permitirán cifrados TLS que no admitan el perfect forward secrecy.

Transparencia de certificado

La transparencia del certificado es un estándar próximo diseñado para poder verificar o auditar los certificados presentados durante la configuración de una conexión HTTPS.

Cuando tu host configura un certificado HTTPS, es emitido por lo que se denomina Autoridad de certificación (CA). La transparencia del certificado apunta a tener un monitoreo cercano a tiempo real para averiguar si un certificado fue emitido maliciosamente o si ha sido emitido por una autoridad certificadora comprometida.

Cuando se emite un certificado, la autoridad certificadora debe enviar el certificado a una serie de registros de certificado de solo anexo, que luego pueden ser verificados por el cliente y analizados por el propietario del dominio. El certificado debe existir en al menos dos registros para que el certificado sea válido.

La clave plist para esta característica es NSRequiresCertificateTransparency. Activar esto hará cumplir la transparencia del certificado. Esto está disponible en iOS 10 y macOS 10.12 y posteriores.

Certificado y Fijación de Clave Pública

Cuando compras un certificado para usar HTTPS en tu servidor, se dice que ese certificado es legítimo porque está firmado con un certificado de una autoridad certificadora intermedia. El certificado utilizado por la autoridad intermedia podría a su vez estar firmado por otra autoridad intermedia, y así sucesivamente, siempre que el último certificado esté firmado por una autoridad de certificación raíz que sea de confianza.

Cuando se establece una conexión HTTPS, estos certificados se presentan al cliente. Esta cadena de confianza se evalúa para garantizar que los certificados estén firmados correctamente por una autoridad de certificación que ya sea de confianza para iOS. (Hay formas de eludir este control y aceptar tu propio certificado autofirmado para la prueba, pero no lo hagas en un entorno de producción).

Si alguno de los certificados en la cadena de confianza no es válido, entonces se dice que el certificado completo no es válido y que tus datos no se enviarán a través de la conexión que no es de confianza. Si bien este es un buen sistema, no es infalible. Existen varias debilidades que pueden hacer que iOS confíe en el certificado de un atacante en lugar de un certificado legítimamente firmado.

Por ejemplo, los proxies de intercepción pueden poseer un certificado intermedio de confianza. Un ingeniero con ingeniería inversa puede instruir manualmente a iOS para que acepte su propio certificado. Además, la política de una corporación puede haber aprovisionado el dispositivo para aceptar su propio certificado. Todo esto lleva a la capacidad de realizar un ataque de "un hombre en el medio" en tu tráfico, lo que permite que se lea. Pero la fijación de certificados evitará que se establezcan conexiones para todos estos escenarios.

La fijación del certificado viene al rescate comprobando el certificado del servidor contra una copia del certificado esperado.

Para implementar la fijación, se debe delegar lo siguiente. Para URLSession, usa lo siguiente:

O para NSURLConnection, puedes usar:

Ambos métodos te permiten obtener un objeto SecTrust de challenge.protectionSpace.serverTrust. Como estamos anulando los delegados de autenticación, ahora debemos llamar explícitamente a la función que realiza las comprobaciones estándar de la cadena de certificados que acabamos de analizar. Haz esto llamando a la función SecTrustEvaluate. Después, podemos comparar el certificado del servidor con uno esperado.

Aquí hay un ejemplo de la implementación.

Para usar este código, configura el delegado de la URLSession al crear tu conexión.

Asegúrate de incluir el certificado en tu paquete de aplicaciones. Si tu certificado es un archivo .pem, necesitarás convertirlo a un archivo .cer en la terminal macOS:

openssl x509 -inform PEM -in mycert.pem -outform DER -out certificate.cer

Ahora, si un atacante cambia el certificado, tu aplicación lo detectará y se negará a realizar la conexión.

Ten en cuenta que algunas bibliotecas de terceros, como AFNetworking, ya son compatibles con la fijación.

Sanitization y Validation

Con todas las protecciones hasta el momento, tus conexiones deben ser bastante seguras contra el hombre en los ataques intermedios. Aun así, una regla importante con respecto a las comunicaciones de red nunca es confiar ciegamente en los datos que estás recibiendo. De hecho, es una buena práctica de programación diseñar por contrato. Las entradas y salidas de tus métodos tienen un contrato que define las expectativas específicas de la interfaz; si la interfaz dice que devolverá un NSNumber, entonces debería hacerlo. Si tu servidor espera una cadena de 24 caracteres o menos, asegúrate de que la interfaz solo devuelva hasta 24 caracteres.

Esto ayuda a prevenir errores inocentes, pero más importante aún, también puede reducir la probabilidad de varios ataques de inyección y corrupción de memoria. Los analizadores comunes, como la clase JSONSerialization, convertirán el texto en tipos de datos Swift donde se pueden realizar estos tipos de pruebas.

Otros analizadores pueden funcionar con objetos equivalentes de Objective-C. Aquí hay una forma de validar que un objeto es del tipo esperado en Swift.

Antes de enviar un delegado a un método, asegúrate de que el objeto sea del tipo correcto para que responda al método; de lo contrario, la aplicación se bloqueará con un error de "selector no reconocido".

Además, puedes ver si un objeto se ajusta a un protocolo antes de intentar enviarle mensajes:

O puedes verificar que coincida con un tipo de objeto de Core Foundation.

Es una buena idea elegir cuidadosamente qué información del servidor puede ver el usuario. Por ejemplo, es una mala idea mostrar una alerta de error que transfiere directamente un mensaje del servidor. Los mensajes de error podrían divulgar la depuración y la información relacionada con la seguridad. Una solución es hacer que el servidor envíe códigos de error específicos que hagan que el cliente muestre mensajes predefinidos.

Además, asegúrate de codificar tus URL para que solo contengan caracteres válidos. El stringByAddingPercentEscapesUsingEncoding de NSString funcionará. Esto no codifica algunos caracteres, como signos de unión y más, pero la función CFURLCreateStringByAddingPercentEscapes permite la personalización de lo que se codificará.

Desinfección de datos de usuario

Al enviar datos a un servidor, ten mucho cuidado cuando cualquier entrada de usuario se transmita a comandos que serán ejecutados por un servidor SQL o un servidor que ejecutará el código. Si bien proteger este servidor contra tales ataques va más allá del alcance de este artículo, como desarrolladores móviles podemos hacer nuestra parte eliminando caracteres del idioma que el servidor está utilizando para que la entrada no sea susceptible a los ataques de inyección de comandos. Los ejemplos pueden ser extraer citas, puntos y comas y barras cuando no sean necesarios para la entrada específica del usuario.

Es una buena práctica limitar la duración de la entrada del usuario. Podemos limitar el número de caracteres escritos en un campo de texto estableciendo el delegado UITextField y luego implementando su método delegado shouldChangeCharactersInRange.

Para un UITextView, el método delegado para implementar esto es:

La entrada del usuario puede validarse aún más para que la entrada tenga el formato esperado. Por ejemplo, si un usuario va a ingresar una dirección de correo electrónico, podemos verificar que sea una dirección válida:

Si un usuario está cargando una imagen al servidor, podemos verificar que sea una imagen válida. Por ejemplo, para un archivo JPEG, los primeros dos bytes y los últimos dos bytes son siempre FF D8 y FF D9.

La lista continúa, pero solo tú como el desarrollador sabrás cuál debe ser la entrada y salida esperada, dados los requisitos de diseño.

URLCache

Los datos que envías a través de la red tienen el potencial de ser guardados en la memoria y en el almacenamiento del dispositivo. Puedes hacer todo lo posible para proteger tus comunicaciones de red, como lo hemos estado haciendo, solo para descubrir que la comunicación se está almacenando.

Varias versiones de iOS han tenido un comportamiento inesperado en lo que respecta a la configuración de caché, y algunas de las reglas de lo que se almacena en caché en iOS siguen cambiando en las versiones. Si bien el almacenamiento en caché ayuda a mejorar el rendimiento de la red al reducir el número de solicitudes, puede ser una buena idea desactivarlo para cualquier dato que consideres altamente confidencial. Puedes eliminar la caché compartida en cualquier momento (como al inicio de la aplicación) llamando a:

Para deshabilitar el almacenamiento en caché a nivel global, usa:

Y si estás utilizando URLSession, puedes desactivar la caché para la sesión de esta manera:

Si estás utilizando un objeto NSURLConnection con un delegado, puedes deshabilitar la caché por conexión con este método delegado:

Y para crear una solicitud de URL que no verifique la caché, usa:

Varias versiones de iOS 8 tenían algunos errores donde algunos de estos métodos por sí solos no hacían nada. Eso significa que es una buena idea implementar todo el código anterior para las conexiones confidenciales, cuando necesites evitar de manera confiable el almacenamiento en caché de las solicitudes de red.

El futuro

Es importante comprender los límites de HTTPS para proteger las comunicaciones de red.

En la mayoría de los casos, HTTPS se detiene en el servidor. Por ejemplo, mi conexión con el servidor de una corporación puede ser a través de HTTPS, pero una vez que el tráfico llega al servidor, no está cifrado. Esto significa que la corporación podrá ver la información que se envió (en la mayoría de los casos), y también significa que la empresa podría usar proxy o pasar esa información de nuevo sin encriptar.

No puedo terminar este artículo sin cubrir un concepto más que es una tendencia reciente: lo que se llama "encriptación de extremo a extremo". Un buen ejemplo es una aplicación de chat cifrada en la que dos dispositivos móviles se comunican entre sí a través de un servidor. Los dos dispositivos crean claves públicas y privadas: intercambian claves públicas, mientras que sus claves privadas nunca salen del dispositivo. Los datos se envían a través de HTTPS a través del servidor, pero primero se cifran con la clave pública de la otra parte de forma que solo los dispositivos que contienen las claves privadas puedan descifrar los mensajes de los demás.

Como una analogía que te ayudará a comprender el cifrado de extremo a extremo, imagínate que quiero que alguien me envíe un mensaje de forma segura que solo yo puedo leer. Por lo tanto le proporciono una caja con un candado abierto (la clave pública) mientras mantengo la llave del candado (clave privada). El usuario escribe un mensaje, lo coloca en la caja, bloquea el candado y me lo envía. Solo yo puedo leer el mensaje porque soy el único con la llave para desbloquear el candado.

Con el cifrado de extremo a extremo, el servidor proporciona un servicio para la comunicación, pero no puede leer el contenido de la comunicación; envían el cuadro bloqueado, pero no tienen la clave para abrirlo. Si bien los detalles de implementación están más allá del alcance de este artículo, es un concepto poderoso si deseas permitir una comunicación segura entre los usuarios de tu aplicación.

Si deseas obtener más información acerca de este enfoque, un lugar para comenzar es el repositorio de GitHub para Open Whisper System, un proyecto de código abierto.

Conclusión

Casi todas las aplicaciones móviles actuales se comunicarán a través de una red, y la seguridad es un aspecto críticamente importante, pero a menudo descuidado, del desarrollo de aplicaciones móviles.

En este artículo, cubrimos algunas de las mejores prácticas de seguridad, que incluyen HTTPS simple, fortalecimiento de aplicaciones de comunicaciones de red, desinfección de datos y cifrado de extremo a extremo. Estas prácticas recomendadas deberían servir como base para la seguridad al codificar tu aplicación móvil.

¡Y mientras estás aquí, echa un vistazo a algunos de nuestros otros tutoriales y cursos de la popular aplicación de iOS!

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.