Categoría de OWASP: MASVS-CODE: Calidad de código
Descripción general
Los riesgos asociados con los permisos personalizados surgen cuando falta la definición de permisos personalizados o se escribe mal, o cuando se hace un uso inadecuado del atributo android:protectionLevel
correspondiente en el manifiesto.
Por ejemplo, estos riesgos se pueden aprovechar mediante la creación de un permiso personalizado con el mismo nombre, pero definido por una app maliciosa, y con diferentes niveles de protección aplicados.
Los permisos personalizados están diseñados para permitir el uso compartido de recursos y capacidades con otras apps. Estos son algunos ejemplos de un uso legítimo de los permisos personalizados:
- Controlar la comunicación entre procesos (IPC) entre dos o más apps
- Acceso a servicios de terceros
- Restringe el acceso a los datos compartidos de una app
Impacto
El impacto de aprovecharse de esta vulnerabilidad es que una app maliciosa podría obtener acceso a recursos que, en principio, se diseñaron para proteger. Las implicaciones de la vulnerabilidad dependen del recurso que se protege y de los permisos asociados al servicio de la aplicación original.
Riesgo: Errores tipográficos de permisos personalizados
Se puede declarar un permiso personalizado en el Manifiesto, pero se utiliza un permiso personalizado diferente para proteger los componentes de Android exportados debido a un error tipográfico. Una aplicación maliciosa puede aprovechar las aplicaciones que tienen errores ortográficos en un permiso de alguna de las siguientes maneras:
- Registrar primero ese permiso
- Anticipación de la ortografía en aplicaciones posteriores
Esto puede permitir que una aplicación acceda sin autorización a los recursos o controle la aplicación víctima.
Por ejemplo, una app vulnerable quiere proteger un componente con un permiso READ_CONTACTS
, pero escribe mal el permiso como READ_CONACTS
por accidente. Una app maliciosa puede reclamar READ_CONACTS
, ya que no es propiedad de ninguna aplicación (ni del sistema) y obtiene acceso al componente protegido. Otra variante común de esta vulnerabilidad es android:permission=True
. Valores como true
y false
, independientemente de las mayúsculas, son entradas no válidas para la declaración de permisos y se tratan de manera similar a otros errores de tipeo de la declaración de permisos personalizados. Para solucionar este problema, el valor del atributo android:permission
debe cambiarse a una cadena de permiso válida. Por ejemplo, si la app necesita acceder a los contactos del usuario, el valor del atributo android:permission
debe ser android.permission.READ_CONTACTS
.
Mitigaciones
Verificaciones de lint de Android
Cuando declares permisos personalizados, usa las verificaciones de lint de Android para ayudarte a encontrar errores tipográficos y otros posibles errores en tu código.
Convención de nombres
Usa una convención de nombres coherente para que los errores tipográficos sean más notorios. Revisa cuidadosamente las declaraciones de permisos personalizados del manifiesto de tu app para detectar errores tipográficos.
Riesgo: permisos huérfanos
Los permisos se usan para proteger los recursos de las apps. Hay dos ubicaciones diferentes en las que una app puede declarar los permisos necesarios para acceder a los recursos:
- AndroidManifest.xml: Se define de forma predeterminada en el archivo AndroidManifest.xml (si no se especifican, se usan permisos
<application>
), p. ej., permiso del proveedor, permiso del receptor, permiso de la actividad, permiso del servicio. - Código: Se registra en el código del entorno de ejecución, p.ej.,
registerReceiver()
.
Sin embargo, a veces, estos permisos no se definen con una etiqueta <permission>
correspondiente en un manifiesto de un APK en el dispositivo. En este caso, se llaman permisos huérfanos. Esta situación puede ocurrir por varios motivos, como los siguientes:
- Podría haber una desincronización entre las actualizaciones del manifiesto y el código con la verificación de permisos.
- Es posible que el APK con los permisos no se incluya en la compilación o que se incluya la versión incorrecta.
- Es posible que el nombre del permiso en la verificación o en el manifiesto esté escrito de forma incorrecta.
Una app maliciosa podría definir un permiso huérfano y adquirirlo. Si esto sucede, las aplicaciones con privilegios que confían en el permiso huérfano para proteger un componente podrían verse comprometidos.
En los casos en que la app con privilegios usa el permiso para proteger o restringir cualquier componente, esto podría otorgar a la app maliciosa acceso a ese componente. Algunos ejemplos son iniciar actividades protegidas por un permiso, acceder a un proveedor de contenido o transmitir a un receptor de emisión protegido por el permiso huérfano.
También podría crear una situación en la que se engañe a la aplicación con privilegios para que crea que la aplicación maliciosa es legítima y, por lo tanto, cargue archivos o contenido.
Mitigaciones
Asegúrate de que todos los permisos personalizados que usa tu app para proteger los componentes también estén definidos en el manifiesto.
La app usa los permisos personalizados my.app.provider.READ
y my.app.provider.WRITE
para proteger el acceso a un proveedor de contenido:
XML
<provider android:name="my.app.database.CommonContentProvider" android:readPermission="my.app.provider.READ" android:writePermission="my.app.provider.WRITE" android:exported="true" android:process=":myappservice" android:authorities="my.app.database.contentprovider"/>
La app también define y usa estos permisos personalizados, lo que evita que otras apps maliciosas lo hagan:
XML
<permission android:name="my.app.provider.READ"/>
<permission android:name="my.app.provider.WRITE"/>
<uses-permission android:name="my.app.provider.READ" />
<uses-permission android:name="my.app.provider.WRITE" />
Riesgo: Uso inadecuado de android:protectionLevel
Este atributo describe el nivel de riesgo potencial en el permiso y también indica qué procedimientos debe seguir el sistema cuando decide si otorgar o no el permiso.
Mitigaciones
Evita el nivel de protección normal o peligroso
Si usas un protectionLevel
normal o peligroso en tus permisos, significa que la mayoría de las apps pueden solicitar y obtener el permiso:
- "normal" solo requiere declararla
- Muchos usuarios aprobarán la opción "peligroso".
Por lo tanto, estos protectionLevels
proporcionan poca seguridad.
Usa permisos de firma (Android >= 10)
Usa niveles de protección de firma siempre que sea posible. El uso de esta función garantiza que solo otras apps firmadas con el mismo certificado que la app que creó el permiso puedan acceder a esas funciones protegidas. Asegúrate de usar un certificado de firma dedicado (no reutilizado) y guárdalo de forma segura en un almacén de claves.
Define un permiso personalizado de la siguiente manera en tu manifiesto:
XML
<permission
android:name="my.custom.permission.MY_PERMISSION"
android:protectionLevel="signature"/>
Restringe el acceso a, por ejemplo, una actividad, solo a las apps a las que se les haya otorgado este permiso personalizado, de la siguiente manera:
XML
<activity android:name=".MyActivity" android:permission="my.custom.permission.MY_PERMISSION"/>
Cualquier otra app que esté firmada con el mismo certificado que la app que declaró este permiso personalizado tendrá acceso a la actividad .MyActivity
y deberá declararlo de la siguiente manera en su manifiesto:
XML
<uses-permission android:name="my.custom.permission.MY_PERMISSION" />
Ten cuidado con los permisos personalizados de firma (Android < 10)
Si tu app se orienta a Android inferior a 10, cada vez que se quiten los permisos personalizados de tu app debido a desinstalaciones o actualizaciones, es posible que haya apps maliciosas que aún puedan usar esos permisos personalizados y, por lo tanto, eludir las verificaciones. Esto se debe a una vulnerabilidad de escalamiento de privilegios (CVE-2019-2200
) que se corrigió en Android 10.
Esta es una de las razones (junto con el riesgo de condiciones de carrera) por las que se recomiendan las verificaciones de firmas en lugar de los permisos personalizados.
Riesgo: condición de carrera
Si una app legítima A
define un permiso personalizado de firma que usan otras apps X
, pero se desinstala posteriormente, una app maliciosa B
puede definir ese mismo permiso personalizado con un protectionLevel
diferente, p.ej., normal. De esta manera, B
obtiene acceso a todos los componentes protegidos por ese permiso personalizado en las apps de X
sin necesidad de firmar con el mismo certificado que la app A
.
Lo mismo sucede si B
se instala antes del A
.
Mitigaciones
Si deseas que un componente esté disponible solo para apps firmadas con la misma firma que la app proveedora, es posible que puedas evitar la definición de permisos personalizados para restringir el acceso a ese componente. En esta situación, puedes usar verificaciones de firma. Cuando una de tus apps realiza una solicitud a otra de tus apps, la segunda puede verificar que ambas estén firmadas con el mismo certificado antes de completar la solicitud.
Recursos
- Cómo minimizar las solicitudes de permisos
- Descripción general de los permisos
- Descripción de los niveles de protección
- CustomPermissionTypo Android Lint
- Cómo usar un Android Lint
- Documento de investigación con una explicación detallada de los permisos de Android y resultados interesantes de las pruebas de fuzz