Skip to content

Most visited

Recently visited

navigation

Sugerencias de seguridad

Android tiene funciones de seguridad integradas en el sistema operativo que reducen notablemente la frecuencia y el impacto de los problemas de seguridad de la app. El sistema está diseñado de modo que puedas compilar tus apps con permisos predeterminados del sistema y de archivos, y evitar tener que tomar decisiones difíciles sobre seguridad.

Entre algunas de las funciones de seguridad principales que te ayudan a compilar apps seguras se incluyen las siguientes:

No obstante, es importante que conozcas las prácticas recomendadas de Android que se explican en este documento. Si sigues estas prácticas como hábitos de codificación generales, reducirás las probabilidades de introducir de forma inadvertida problemas de seguridad que perjudiquen a tus usuarios.

Almacenamiento de datos

El problema de seguridad más común para una aplicación en Android es si otras apps pueden acceder a los datos que guardaste en el dispositivo. Existen tres formas básicas de guardar datos en el dispositivo:

Uso del almacenamiento interno

De forma predeterminada, solo tu app puede acceder a los archivos que creas en el almacenamiento interno. Android implementa esta protección y es suficiente para la mayoría de las aplicaciones.

En general, debes evitar usar los modos MODE_WORLD_WRITEABLE o MODE_WORLD_READABLE para archivos de IPC, ya que no ofrecen la capacidad de limitar el acceso a datos para aplicaciones específicas ni te permiten controlar el formato de los datos. Si deseas compartir tus datos con otros procesos de la app, deberías considerar usar en su lugar un proveedor de contenido, que ofrece permisos de lectura y escritura a otras apps y puede otorgar permisos de forma dinámica según, caso por caso.

Para ofrecer protección adicional para datos confidenciales, podrías optar por encriptar los archivos locales con una clave a la cual la aplicación no pueda acceder directamente. Por ejemplo, puedes disponer una clave en un KeyStore y protegerla con una contraseña de usuario que no esté almacenada en el dispositivo. Si bien esto no protege los datos de un compromiso en la raíz que puede controlar al usuario que ingresa la contraseña, puede brindar protección para un dispositivo perdido sin encriptación del sistema de archivos.

Uso de almacenamiento externo

Los archivos creados en un almacenamiento externo, como una tarjeta SD, pueden leerse y escribirse a nivel global. Debido a que el almacenamiento externo puede ser eliminado por el usuario y modificado por cualquier aplicación, no debes almacenar información privada mediante almacenamiento externo.

Como ocurre con los datos de cualquier fuente no segura, debes realizar validación de entrada cuando manejes datos de un almacenamiento externo. Te recomendamos no almacenar archivos ejecutables ni de clase en un medio de almacenamiento externo antes de realizar una carga dinámica. Si tu app obtiene archivos ejecutables de medios de almacenamiento externo, los archivos deben estar firmados y verificados criptográficamente antes de la carga dinámica.

Uso de proveedores de contenido

Los proveedores de contenido ofrecen un mecanismo de almacenamiento externo que puede limitarse a tu aplicación o exportarse para permitir el acceso a otras aplicaciones. Si no pretendes permitir que otras aplicaciones accedan a tu ContentProvider, márcalas como android:exported=false en el manifiesto de la aplicación. De lo contrario, fija el atributo android:exported en "true" para permitir que otras apps accedan a los datos almacenados.

Al crear un ContentProvider que se exportará para que otras aplicaciones lo usen, puedes especificar un solo permiso de lectura y escritura, o permisos específicos de lectura y escritura en el manifiesto. Te recomendamos que limites tus permisos a los necesarios para realizar la tarea prevista. Recuerda que generalmente es más fácil agregar permisos posteriormente para exponer nuevas funcionalidades que quitarlos y perjudicar a los usuarios existentes.

Si usas un proveedor de contenido para compartir datos solo entre tus apps, es preferible que uses el atributo android:protectionLevel configurado en el nivel de protección "signature". Los permisos de firma no requieren la confirmación del usuario, por lo que proporcionan una mejor experiencia para este y un acceso más controlado a los datos del proveedor de contenido cuando las apps que acceden al contenido se firman con la misma clave.

Los proveedores de contenido también pueden proporcionar acceso más detallado al declarar el atributo android:grantUriPermissions y usar los indicadores FLAG_GRANT_READ_URI_PERMISSION y FLAG_GRANT_WRITE_URI_PERMISSION en el objeto Intent que activa el componente. <grant-uri-permission element> Puede limitar aún más el alcance de estos permisos.

Al acceder al proveedor de contenido, usa métodos de consulta con parámetros como query(), update() y delete() para evitar la posible inserción de SQL desde fuentes no seguras. Ten en cuenta que el uso de métodos con parámetros no es suficiente si el argumento selection se compiló mediante la concatenación de datos del usuario antes de enviarlo al método.

Debes evitar la idea errónea de que el permiso de escritura proporcionará seguridad. Ten en cuenta que este permite declaraciones SQL que posibilitan la confirmación de algunos datos usando cláusulas WHERE creativas y analizando los resultados. Por ejemplo, un atacante podría comprobar la presencia de un número de teléfono específico en un registro de llamadas al modificar una fila solo si ese número de teléfono ya existe. Si los datos del proveedor de contenido tienen una estructura previsible, el permiso de escritura puede ser equivalente a proporcionar ambos permisos, de lectura y escritura.

Uso de permisos

Debido a que Android aísla las aplicaciones entre sí, estas deben compartir recursos y datos explícitamente. Hacen esto declarando los permisos que necesitan para capacidades adicionales no previstas por la zona de pruebas básica, incluido el acceso a funciones del dispositivo como la cámara.

Solicitud de permisos

Te recomendamos minimizar la cantidad de permisos que tu app solicite. La falta de acceso a permisos sensibles reduce el riesgo de usar esos permisos de forma inadvertida y errónea, puede mejorar la captación de usuarios y hace que tu app sea menos vulnerable para los atacantes. En general, si no se requiere un permiso para que tu app funcione, no solo solicites.

Puedes diseñar tu aplicación de modo que no requiera permisos, algo que se recomienda. Por ejemplo, en lugar de solicitar acceso a información del dispositivo para crear un identificador único, crea un GUID para tu aplicación (consulta la sección Manejo de datos de usuario). Como alternativa, en lugar de usar almacenamiento externo (que requiere permiso) puedes guardar datos en el almacenamiento interno.

Además de solicitar permisos, tu aplicación puede usar <permissions> para proteger IPC que conlleve riesgos de seguridad y se exponga a otras aplicaciones, como ContentProvider. En general, recomendamos usar controles de acceso que no sean permisos confirmados por los usuarios cuando sea posible, ya que los permisos pueden resultar confusos para estos. Por ejemplo, considera usar el nivel de protección de firma en permisos para comunicación IPC entre aplicaciones ofrecidas por un mismo desarrollador.

No permitas que se fuguen datos protegidos con permisos. Esto ocurre cuando tu app expone, a través de IPC, datos que están disponibles únicamente porque tu app tiene permiso para acceder a ellos. Es posible que los clientes de la interfaz IPC de tu app no tengan ese mismo permiso de acceso a datos. Puedes encontrar más información sobre la frecuencia y los posibles efectos de este problema en este informe de investigación, publicado en USENIX.

Creación de permisos

Generalmente, debes esforzarte por definir la menor cantidad de permisos posible sin dejar de cumplir con tus requisitos de seguridad. Crear un permiso nuevo es relativamente poco común para la mayoría de las aplicaciones, ya que los permisos definidos por el sistema abarcan muchas situaciones. Cuando corresponda, realiza comprobaciones de acceso usando los permisos existentes.

Si debes crear un permiso nuevo, considera la posibilidad de realizar la tarea con un nivel de protección “signature”. Los permisos de firma son transparentes para el usuario y solo permiten el acceso de aplicaciones firmadas por el mismo desarrolladores que firmó la aplicación que realiza la comprobación de permisos.

Si creas un permiso con el nivel de protección “dangerous”, debes considerar algunas complejidades:

Estas opciones te presentan un desafío no técnico como desarrollador y también confunden a tus usuarios, motivo por el cual desalentamos el uso del nivel de permiso “dangerous”.

Uso de red

Las transacciones en red son, por naturaleza, riesgosas para la seguridad, ya que incluyen la transmisión de datos del usuario que podrían ser privados. Las personas son cada vez más conscientes de los problemas de seguridad de un dispositivo móvil, en especial cuando el dispositivo realiza transacciones en red, por lo cual es muy importante que tu app implemente todas las prácticas recomendadas para proteger la seguridad de los datos del usuario en todo momento.

Uso de redes IP

Realizar operaciones en red Android no es muy diferente en comparación con otros entornos de Linux. La consideración clave es asegurarte de usar los protocolos correctos para datos confidenciales, como HttpsURLConnection para tráfico web seguro. Preferimos usar HTTPS en lugar de HTTP siempre que se admita HTTPS en el servidor, ya que los dispositivos móviles con frecuencia se conectan a redes no protegidas, como hotspots Wi-Fi públicos.

La comunicación a nivel de socket autenticada y encriptada puede implementarse fácilmente usando la clase SSLSocket. Dada la frecuencia con la que los dispositivos Android se conectan a redes inalámbricas no seguras por Wi-Fi, se recomienda el uso de redes seguras para todas las aplicaciones que se comunican a través de la red.

Hemos visto que algunas aplicaciones usan puertos de red localhost para manejar IPC sensibles. No recomendamos este enfoque, ya que otras apps del dispositivo pueden acceder a esas interfaces. Como alternativa, debes usar un mecanismo de IPC de Android en el que se pueda realizar la autenticación con un Service, por ejemplo. (Peor aun que usar un bucle invertido es establecer vinculaciones con INADDR_ANY, ya que tu aplicación puede recibir solicitudes desde cualquier lugar).

Asimismo, un problema común que merece que lo repitamos es que debes asegurarte de no confiar en los datos descargados de HTTP u otros protocolos inseguros. Esto incluye la validación de entrada en WebView y todas las respuestas a intents emitidas por HTTP.

Uso de red de telefonía

El protocolo SMS se diseñó principalmente para la comunicación entre usuarios y no es adecuado para apps que intenten transferir datos. Debido a las limitaciones de este protocolo, te recomendamos usar Google Cloud Messaging (GCM) y redes IP para enviar mensajes de datos de un servidor web a tu app en un dispositivo móvil.

Ten en cuenta que el protocolo SMS no dispone de encriptación ni autenticación sólida en la red ni en el dispositivo. En particular, cualquier receptor de SMS debe prever que un usuario malicioso puede haber enviado el SMS a una aplicación; para realizar comandos sensibles, no confíes en datos de SMS sin autenticación. También debes tener en cuenta que el protocolo SMS puede estar expuesto a falsificación de identidad o interceptación en la red. En el dispositivo Android, los mensajes SMS se transmiten como intents de transmisión, de modo que otras aplicaciones que tengan el permiso READ_SMS podrán leerlos o capturarlos.

Cómo realizar una validación de entrada

La validación de entrada insuficiente es uno de los problemas de seguridad más comunes que afectan a las aplicaciones, independientemente de la plataforma en la que se ejecuten. Android tiene medidas de prevención a nivel de plataforma que reducen la exposición de las aplicaciones a problemas de validación de entrada, y debes usar esas funciones siempre que sea posible. Ten en cuenta también que esa selección de lenguajes con seguridad de tipos tiende a reducir las probabilidades de que se presenten problemas de validación de entrada.

Si usas código nativo, los datos leídos de archivos recibidos a través de la red o de una IPC pueden introducir un problema de seguridad. Los problemas más comunes son los errores de desbordamiento del búfer, de uso después de liberación y por un paso. Android proporciona varias tecnologías, como ASLR y DEP, que reducen la posibilidad de explotar de esos errores, pero no resuelven el problema subyacente. Puedes evitar estas vulnerabilidades manejando punteros y administrando búferes cuidadosamente.

Los lenguajes dinámicos basados en strings, como JavaScript y SQL, también están expuestos a problemas de validación de entrada debido a caracteres de escape e inyección de strings.

Si usas datos en las consultas que se envían a una base de datos SQL o un proveedor de contenido, la inserción de SQL puede ser un problema. La mejor defensa consiste en usar consultas con parámetros, como se discutió en la sección anterior sobre proveedores de contenido. Limitar los permisos a solo lectura o escritura también puede reducir las posibilidades de daños relacionados con la inyección de SQL.

Si no puedes usar las funciones de seguridad que mencionamos antes, te recomendamos usar formatos de datos bien estructurados y verifiques que los datos coincidan con el formato previsto. Si bien incluir caracteres o reemplazo de caracteres en lista negra puede ser una estrategia eficaz, técnicas como esta son propensas a generar errores en la práctica y deben evitarse siempre que sea posible.

Manejo de datos de usuario

En general, el mejor enfoque para la seguridad de los datos de usuario implica minimizar el uso de API que accedan a datos de usuario confidenciales o privados. Si tienes acceso a datos de usuario y puedes evitar almacenar o transmitir la información, no almacenes ni transmitas los datos. Por último, considera la posibilidad de que exista una forma de implementar la lógica de tu aplicación usando un hash o una forma irreversible de los datos. Por ejemplo, tu aplicación podría usar el hash de una dirección de correo electrónico como clave principal para evitar la transmisión o el almacenamiento de la dirección de correo electrónico. Esto reduce las posibilidades de exponer los datos de forma accidental, y también las probabilidades de que los atacantes intenten vulnerar tu aplicación.

Si tu aplicación accede a información personal, como contraseñas o nombres de usuario, recuerda que algunas jurisdicciones podrían solicitar que proporciones una política de privacidad en la que expliques el uso y almacenamiento de esos datos. Por lo tanto, seguir la práctica recomendada de minimizar el acceso a datos de usuario también podría simplificar el cumplimiento.

También debes considerar la posibilidad de que tu aplicación, de forma inadvertida, deje expuesta información personal a otros; por ejemplo, componentes externos para publicidad o servicios externos que tu aplicación usa. Si no sabes la razón por la cual un componente o servicio requieren información personal, no la proporciones. En general, reducir el acceso a información personal por parte de tu aplicación reducirá las probabilidades de que ocurran problemas en esta área.

Si se requiere acceso a datos sensibles, evalúa si esa información se debe transmitir a un servidor, o si la operación puede realizarse en el cliente. Considera ejecutar en el cliente cualquier código que use datos confidenciales para evitar la transmisión de datos de usuarios.

Asegúrate también de no exponer datos de usuarios de forma inadvertida a otra aplicación del dispositivo a través de IPC excesivamente permisivas, archivos que admiten escritura pública o sockets de red. Este es un caso especial de fuga de datos protegidos con permisos, que se analiza en la sección Solicitud de permisos.

Si se requiere un GUID, crea un número extenso y único, y guárdalo. No uses identificadores de teléfono, como el número de teléfono o IMEI, que puedan estar asociados con información personal. Este tema se analiza en mayor profundidad en el blog para desarrolladores de Android.

Ten cuidado cuando realices operaciones de escritura en registros del dispositivo. En Android, los registros son un recurso compartido, y están disponibles para una aplicación con el permiso READ_LOGS. Si bien los datos del registro del teléfono son temporales y se borran durante el reinicio, el registro inadecuado de información de usuarios podría filtrar de forma inadvertida datos de estos a otras aplicaciones.

Uso de WebView

Debido a que WebView consume contenido web que puede incluir HTML y JavaScript, el uso inadecuado puede introducir problemas comunes de seguridad web como secuencias de comando en diferentes sitios (inyección de JavaScript). En Android se incluyen varios mecanismos para reducir el alcance de estos posibles problemas al limitar la capacidad de WebView a la funcionalidad mínima requerida por tu aplicación.

Si tu aplicación no usa JavaScript directamente en un WebView, no llames a setJavaScriptEnabled(). En el ejemplo de código se usa este método, que deberías rediseñar en la aplicación de producción, por lo cual debes quitar esa llamada al método si no es necesaria. De forma predeterminada, WebView no ejecuta JavaScript. Por ello, no es posible usar secuencias de comandos en diferentes sitios.

Usa addJavaScriptInterface() con especial precaución, ya que permite que JavaScript invoque operaciones normalmente reservadas para aplicaciones de Android. Si la usas, muestra addJavaScriptInterface() solo a páginas web cuyas entradas sean por completo confiables. Si se permiten entradas no seguras, JavaScript no seguro podría invocar métodos de Android en tu app. En general, te recomendamos mostrar addJavaScriptInterface() solo a JavaScript dentro del APK de tu aplicación.

Si tu aplicación accede a datos sensibles con un WebView, te recomendamos usar el método clearCache() para eliminar los archivos almacenados localmente. Los encabezados del servidor, como no-cache, también pueden usarse para indicar que una aplicación no debe almacenar en caché determinado contenido.

Los dispositivos con plataformas anteriores a Android 4.4 (nivel de API 19) usan una versión de webkit que presenta algunos problemas de seguridad. Como solución temporal, si tu app se ejecuta en esos dispositivos, debe confirmar que los objetos WebView solo muestren contenido de confianza. También debes usar el objeto Provider de seguridad actualizable para asegurarte de que tu app no esté expuesta a posibles vulnerabilidades en SSL, como se describe en Cómo actualizar tu proveedor de seguridad para protegerte contra vulnerabilidades de SSL. Si tu aplicación debe representar contenido de la Web abierta, considera proporcionar tu propio representador para poder mantenerlo actualizado con los últimos parches de seguridad.

Manejo de credenciales

En general, recomendamos minimizar la frecuencia con la que se solicitan credenciales de usuario, a fin de que los ataques de suplantación de identidad sean más perceptibles y su éxito sea menos probable. En su lugar, usa un token de autorización y actualízalo.

Cuando sea posible, no se debe almacenar el nombre de usuario y la contraseña en el dispositivo. Como alternativa, realiza la autenticación inicial usando el nombre de usuario y la contraseña que haya proporcionado este, y luego usa un token de autorización de corta duración específico para el servicio.

El acceso a los servicios que permitirán acceder a varias aplicaciones debe concretarse usando AccountManager. Si es posible, usa la clase AccountManager para invocar un servicio basado en la nube y no almacenes contraseñas en el dispositivo.

Después de usar AccountManager para recuperar una Account, incluye CREATOR antes de pasar credenciales a fin de no transmitirlas accidentalmente a la aplicación incorrecta.

Si solo las aplicaciones que tú crees usarán credenciales, puedes verificar la aplicación que acceda al AccountManager usando checkSignature(). Como opción, podrías usar un KeyStore para el almacenamiento si solo una aplicación usará la credencial.

Uso de criptografía

Además de proporcionar aislamiento de datos, admitir la encriptación en todo el sistema de archivos y proporcionar canales de comunicación seguros, Android proporciona una amplia variedad de algoritmos para proteger los datos que usan criptografía.

En general, intenta usar el nivel más alto de implementación de framework preexistente que pueda admitir tu caso de uso. Si necesitas recuperar de forma segura un archivo de una ubicación conocida, un simple URI HTTPS puede ser adecuado y no requiere conocimientos de criptografía. Si necesitas un túnel seguro, considera usar HttpsURLConnection o SSLSocket, en lugar de escribir tu propio protocolo.

Si crees que no necesitas implementar tu propio protocolo, te recomendamos no implementar tus propios algoritmos criptográficos. Usa algoritmos criptográficos existentes como los de la implementación de AES o RSA, proporcionados en la clase Cipher.

Usa un generador de números aleatorios seguro, SecureRandom, para inicializar las claves criptográficas, KeyGenerator. El uso de una clave que no se cree con un generador de números aleatorios seguro debilitará notablemente la protección del algoritmo y podría permitir ataques sin conexión.

Si debes almacenar una clave para volver a usarla, emplea un mecanismo como KeyStore, que proporciona un mecanismo para el almacenamiento y la recuperación de claves criptográficas a largo plazo.

Uso de comunicación entre procesos

Algunas apps intentan implementar IPC usando métodos tradicionales de Linux, como sockets de red y archivos compartidos. Te alentamos enfáticamente a que, en su lugar, uses funcionalidades del sistema Android para IPC, como Intent, Binder o Messenger con un Service y BroadcastReceiver. Los mecanismos de IPC de Android te permiten verificar la identidad de la aplicación que se conecta a tu IPC y establecer una política de seguridad para cada mecanismo de IPC.

Muchos de los elementos de seguridad se comparten entre mecanismos de IPC. Si tu mecanismo de IPC no está pensado para que otras aplicaciones puedan usarlo, configura el atributo android:exported en "false" en el elemento manifest del componente, al igual que para el elemento <service>. Esto resulta útil para aplicaciones que consisten en varios procesos dentro del mismo UID, o, si decides en un momento avanzado del desarrollo que no deseas exponer funcionalidad como IPC, pero tampoco deseas volver a escribir el código.

Si tu IPC admite el acceso de otras aplicaciones, puedes aplicar una política de seguridad usando el elemento <permission>. Si la IPC está entre dos apps independientes firmadas con la misma clave, es preferible usar el nivel de permiso "signature" en el android:protectionLevel.

Uso de intents

Las intents son el mecanismo preferido para establecer IPC asincrónicas en Android. Según los requisitos de tu aplicación, podrías usar sendBroadcast(), sendOrderedBroadcast() o una intent explícita para un componente específico de la aplicación.

Ten en cuenta que las transmisiones solicitadas pueden ser “consumidas” por un destinatario, por lo que no se deben entregar a todas las aplicaciones. Si envías una intent que se deba entregar a un receptor específico, debes usar una intent explícita que declare el receptor mediante nameintent.

Los emisores de una intent pueden verificar que el receptor tenga un permiso que especifique un permiso que no sea null con la llamada al método. Solo las aplicaciones con ese permiso recibirán la intent. Si los datos de una intent de transmisión pueden ser confidenciales, debes considerar aplicar un permiso para asegurarte de que las aplicaciones maliciosas no puedan registrarse y recibir esos mensajes sin los permisos correspondientes. En esas circunstancias, también puedes considerar invocar al receptor directamente, en lugar de generar una transmisión.

Nota: Los filtros de intents no deben considerarse como una función de seguridad; los componentes pueden invocarse con intents específicos y es posible que tengan datos que coincidan con el filtro de intents. Debes realizar una validación de entrada en tu receptor de intents a fin de confirmar que tenga el formato correcto para el receptor, el servicio o la actividad invocados.

Uso de servicios

Un Service generalmente se usa para brindar funcionalidad que usen otras aplicaciones. Cada clase de servicio debe tener una declaración de <service> correspondiente en su archivo de manifiesto.

De forma predeterminada, los servicios no se exportan y no pueden ser invocados por ninguna otra aplicación. No obstante, si agregas filtros de intents en la declaración del servicio, la exportación se realiza de forma predeterminada. La mejor opción será declarar explícitamente el atributo android:exported para asegurarte de que se comporte como lo desees. Los servicios también pueden protegerse usando el atributo android:permission. Al hacerlo, otras aplicaciones deberán declarar un elemento <uses-permission> correspondiente en su propio manifiesto para poder iniciar y detener un servicio, o realizar la vinculación a este.

Un servicio puede proteger, mediante permisos, llamadas de IPC individuales que reciba llamando a checkCallingPermission() antes de ejecutar la implementación de esa llamada. Generalmente, recomendamos usar permisos declarativos en el manifiesto debido a que están menos expuestos a la omisión.

Uso de interfaces binder y messenger

El uso de Binder o Messenger es el mecanismo preferido para IPC de estilo RPC en Android. Proporcionan una interfaz bien definida que habilita la autenticación mutua de los puntos finales, si es necesario.

Recomendamos diseñar interfaces de modo que no se requieran comprobaciones de permisos específicos de la interfaz. Los objetos Binder y Messenger no se declaran en el manifiesto de la aplicación y, por lo tanto, no puedes aplicarles permisos declarativos directamente. Generalmente, heredan los permisos declarados en el manifiesto de la aplicación para el Service o la Activity en los que se implementan. Si creas una interfaz que requiere autenticación o controles de acceso, esos controles se deben agregar de forma explícita como código en la interfaz Binder o Messenger.

Si proporcionas una interfaz que no requiere controles de acceso, usa checkCallingPermission() para verificar si el emisor tiene un permiso obligatorio. Esto tiene particular importancia antes de acceder a un servicio en nombre del emisor, ya que se pasa la identidad de tu aplicación a otras interfaces. Si invocas una interfaz proporcionada por un Service, la invocación de bindService() puede fallar si no tienes permiso para acceder al servicio específico. Si llamas a una interfaz proporcionada localmente por tu propia aplicación, puede ser útil usar la clearCallingIdentity() para cumplir con comprobaciones de seguridad internas.

Para obtener más información sobre cómo realizar IPC con un servicio, consulta Servicios enlazados.

Uso de receptores de mensajes

Un BroadcastReceiver controla solicitudes asincrónicas iniciadas por un Intent.

De forma predeterminada, los receptores se exportan y pueden invocarse a través de cualquier otra aplicación. Si tu BroadcastReceiver está pensado para que otras aplicaciones puedan usarlo, te recomendamos aplicar permisos de seguridad a los receptores usando el elemento <receiver> en el manifiesto de la aplicación. Esto evitará que las aplicaciones sin los permisos adecuados envíen una intent al BroadcastReceiver.

Carga dinámica de código

No recomendamos cargar código desde fuera del APK de tu aplicación. Hacerlo aumenta notablemente las probabilidades de que se comprometa la aplicación por la inserción o manipulación de código. También suma complejidad a la administración de versiones y la prueba de aplicaciones. Por último, puede imposibilitar la verificación del comportamiento de una aplicación, por lo cual podría estar prohibida en algunos entornos.

Si tu aplicación carga código de forma dinámica, lo más importante que debes recordar acerca del código cargado dinámicamente es que se ejecuta con los mismos permisos de seguridad que el APK de la aplicación. El usuario tomó la decisión de instalar tu aplicación en función de tu identidad, y espera que le proporciones todo el código necesario en la aplicación, incluido el código de carga dinámica.

El principal riesgo de seguridad asociado con la carga dinámica de código es que este debe provenir de una fuente verificable. Si los módulos se incluyen directamente en tu APK, no podrán modificarse a través de otras aplicaciones. Esto es así, independientemente de que el código sea una biblioteca nativa o una clase cargada con DexClassLoader. Hemos visto muchas instancias de aplicaciones que intentan cargar código de fuentes inseguras, como código descargado de la red mediante protocolos sin encriptar o de ubicaciones que admiten escritura pública, como medios de almacenamiento externo. Esas ubicaciones podrían permitir que alguien en la red modifique el contenido en tránsito, o que otra aplicación del dispositivo del usuario modifique el contenido en el dispositivo, respectivamente.

Seguridad en una máquina virtual

Dalvik es la máquina virtual (MV) en tiempo de ejecución de Android. Dalvik se compiló específicamente para Android, pero muchas de las inquietudes en relación con el código seguro en otras máquinas virtuales también se aplican para Android. En general, no deberías preocuparte por los problemas de seguridad relacionados con la máquina virtual. Tu aplicación se ejecuta en un entorno de prueba seguro. Por lo tanto, los procesos del sistema no pueden acceder a tu código ni a información privada.

Si deseas ver el tema de la seguridad de máquinas virtuales en mayor profundidad, te recomendamos familiarizarte con la bibliografía existente sobre el tema. Los siguientes son dos de los recursos más importantes:

Este documento se centra en las áreas específicas para Android o diferentes de otros entornos de MV. Para los desarrolladores con experiencia en programación de MV en otros entornos, hay dos aspectos amplios que podrían ser diferentes respecto de la escritura de apps para Android:

Seguridad en código nativo

En general, alentamos a los desarrolladores a usar Android SDK para el desarrollo de aplicaciones en lugar de código nativo con Android NDK. Las aplicaciones compiladas con código nativo son más complejas, menos portátiles, y más propensas a incluir errores comunes de daños en la memoria, como los desbordamientos del búfer.

Para las compilaciones de Android se emplea el kernel de Linux. Por lo tanto, conocer las prácticas recomendadas sobre seguridad en el desarrollo para Linux resultará particularmente útil si planeas usar código nativo. Las prácticas de seguridad de Linux no se contemplan en este documento, pero uno de los recursos más populares es “Secure Programming for Linux and Unix HOWTO”, disponible en http://www.dwheeler.com/secure-programs.

Una diferencia importante entre Android y la mayoría de los entornos Linux es la zona de pruebas de aplicaciones. En Android, todas las aplicaciones se ejecutan en la zona de pruebas de aplicaciones, incluidas las que se escriben con código nativo. En el nivel más básico, una buena manera de pensar en esto para los desarrolladores con conocimientos de Linux es saber que a cada aplicación se le asigna un UID único con permisos muy limitados. Esto se discute en mayor profundidad en Información general de seguridad de Android, y debes familiarizarte con los permisos de aplicaciones aun cuando uses código nativo.

This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields

Hooray!

Follow Google Developers on WeChat

Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a short survey?
Help us improve the Android developer experience.
(Sep 2017 survey)