Isolamento e segurança aplicacional em Android
Por Pedro Veloso para o PPLWARE.COM A razão pela qual decidi fazer este artigo prende-se com uma questão que vi colocada no G+ em que essencialmente perguntam se é possível uma aplicação ler dados e mesmo injectar código para outra aplicação em Android.
Apesar desse post ter sido o pretexto para o artigo, reconheço que esta questão surge com bastante frequência na Internet e que muita coisa é dita erradamente sobre o Sistema Operativo Android portanto espero elucidar algumas dessas questões relativas ao isolamento aplicacional de Android.
O Android quando foi projectado tinha em vista a cooperação de aplicações entre si, uma filosofia que também está presente nos sistemas operativos inspirados em Unix. Outros sistemas como o iOS e o Windows Mobile não se apoiam tanto nesta filosofia (embora também tenham alguns mecanismos para o mesmo fim), e a forma como isso está implementado traz vantagens e desvantagens ao Android que passarei a explicar ao longo do artigo.
Desenho do sistema
Aqui descrevo como o Android está construído e qual o seu comportamento de omissão.
Quando uma aplicação é instalada no Android é-lhe atribuído um utilizador e grupo únicos, isto tira partido da base de Linux que constitui o Android. Derivado a isto, os dados privados da aplicação (tipicamente guardados em /data/data/[nome do pacote da aplicação]/
) ficam com o owner igual a esse ID único de utilizador e atributos drwx------
, ou seja essa pasta e os ficheiros subordinados podem apenas ser acedidos pela própria aplicação. Existe ainda a possibilidade de serem acedidos pelo utilizador Root (utilizador com ID 0) que é o administrador de sistema, e por vezes pelo utilizador System (utilizador com ID 1000). Ou seja, tal como seria de esperar e por definição o utilizador Root tem acesso ao sistema completo, mas em Android uma aplicação só consegue privilégios Root se o utilizador o permitir.
Uma aplicação pode obter permissões de System se vier instalada na partição de aplicações da ROM (/system/app), ou seja, são aplicações como Gmail e Google Maps e todas as outras que vêm pré-instaladas com a ROM. Não é possível numa instalação a aplicação ser instalada como aplicação de sistema, e nem todas as aplicações que são de sistema têm este privilégio. As aplicações de sistema têm a particularidade de permanecem instaladas mesmo após uma reposição de dados (mais usualmente conhecido como Factory Reset),
Partilha de Informação
Em Desenho do sistema falei do mecanismo que previne que uma aplicação aceda aos dados de outra, essa imposição é feita a nível do sistema de ficheiros e do kernel de Linux.
No entanto, tal como tinha referido no início deste artigo o Android é um sistema construído para que seja possível às aplicações partilharem informações de forma fácil e eficaz entre si.
O primeiro mecanismo que vou falar e um que é muito importante em Android é o conceito de ContentProvider. ContentProvider é um bloco de construção de aplicações que permite oferecer informações a outras aplicações. Um bom exemplo desta funcionalidade é a aplicação de Contactos do telemóvel, esta usa um ContentProvider para oferecer alguns dos detalhes dos contactos a aplicações que queiram ler estes recursos, isto faz com que não se tenha de reinventar a roda para coisas como procura de informações de contactos guardados no telemóvel. Há 2 particularidades importantes sobre ContentProviders:
- A aplicação que faz uso do ContentProvider é que escolhe qual e como é que a informação é fornecida às outras aplicações.
- Uma aplicação para tirar partido do ContentProvider de outra aplicação irá ser sinalizada com uma permissão relativa a esse propósito, e o utilizador será informado de tal.
Portanto com ContentProvider toda da informação que é passada a outras aplicações está no controlo do programador.
Existem vários outros mecanismos que permitem a troca de informação entre aplicações:
- IPC (Inter-Process Communication). Em Android é possível fornecer acesso a métodos previamente escolhidos da aplicação a aplicações externas através de AIDL. O programador define num ficheiro quais os métodos que a outras aplicações podem ter acesso, e a outra aplicação tem de incorporar este mesmo ficheiro para comunicar com um serviço da aplicação que fornece os métodos. Este mecanismo é muito útil quando queremos ter mais do que 1 aplicação a trabalhar para o mesmo propósito em simultâneo no sistema. Um exemplo disto seria por exemplo uma framework proprietária de uma marca que tem vários serviços que podem tirar partido desta funcionalidade para comunicarem entre si.
- SharedUserId: tal como tinha referido, em Android cada aplicação tem um User ID único que lhe é atribuído aquando a instalação da aplicação. No entanto se quisermos explicitamente que duas aplicações possam ler a informação uma da outra podemos definir isso no Android Manifest com os atributos
android:sharedUserId
eandroid:sharedUserLabel
. Isto faz pensar, "então se uma aplicação usar isto posso também colocar a mesma sharedUserID na minha aplicação e tirar partido dos dados privados da aplicação?", a resposta é NÃO porque para utilizar esta funcionalidade ambas as aplicações têm de estar assinadas com a mesma assinatura digital que é usada na altura de compilação da aplicação, e esaa assinatura (a menos que tenha sido roubada ou partilhada) está apenas na posse do programador da aplicação.
- SharedPreferences: Este é o método de omissão para guardar as definições de uma aplicação em Android. Muitos programadores iniciantes da plataforma desconhecem isto, apesar do nome parecer indicá-lo bem, é possível partilhar estas definições com outras aplicações. Estas definições quando guardadas pela primeira vez definem o tipo de acesso. Exemplo:
- MODE_PRIVATE: valor 0
- MODE_WORLD_READABLE : valor 1
- MODE_WORLD_WRITABLE: valor 2
Este seria o acesso correcto para guardar a informação de forma privada:
SharedPreferences prefs = c.getSharedPreferences(USER_NICKNAME, Context.MODE_PRIVATE);
O que muitos programadores (MÁ PRÁTICA!!) fazem é usar o declarativo numérico ao invés da Constante definida na class Context, e muitas vezes nem se apercebem da importância desta definição. As definições existentes de acesso são as seguintes:
O erro está quando a definição é feita deste modo:
SharedPreferences prefs = c.getSharedPreferences(USER_NICKNAME, 3);
Ora, 3 significa na verdade MODE_WORLD_READABLE + MODE_WORLD_WRITABLE , o que quer dizer que apesar das preferências da aplicação estarem numa directoria cujo acesso é negado a outras aplicações por herança de atributos (/data/data/[package name da aplicação]/shared_prefs/
) os seus atributos foram sinalizados como legíveis para outras aplicações. Este é um exemplo de como o mecanismo de partilha de conteúdos pode ser mal utilizado ou menosprezado pelo utilizador levando a que a informação seja acessível por outras aplicações.
Outras más práticas
Tal como evidenciado no exemplo anterior, também o mau uso de IPC e de ContentProvider podem levar à partilha indesejada de informação. Nesses casos ninguém tem mais culpa que o programador pois este ignorou ou utilizou erradamente os mecanismos de sistema que estavam bem construídos.
Um caso em que isto já não é absolutamente verdade é quando os dados estão guardados no cartão de memória. Uma vez que o sistema de ficheiros do cartão de memória é FAT32 (uma decisão que foi tomada para que os conteúdos do cartão sejam legíveis em sistemas Microsoft Windows), este sistema de ficheiros rudimentar (:P) não permite ter um controlo de permissões suficiente como o de armazenamento interno, então aqui qualquer aplicação pode aceder a qualquer conteúdo do cartão de memória, tendo no entanto que ter definida a permissão de leitura de cartão do mesmo (e que como é claro será apresentada ao utilizador em tempo de instalação), mas após a obter não existe um controlo de que tipo de conteúdo no cartão lhe é inacessível. Aqui a única solução passa pela aplicação implementar algum tipo de encriptação dos dados que guarda se de facto quer que estes não sejam facilmente legíveis por outras aplicações.
Falhas de sistema
Em Android, tal como noutro sistema operativo móvel qualquer, existem falhas de sistema que podem permitir tirar o extravio de informação.
Uma falha habitualmente explorada é a obtenção de Root sem consentimento do utilizador, uma vez que a aplicação tenha permissões Root é-lhe possível ler toda a informação do sistema (a menos que cifrada).
Este tipo de exploit tem algumas complicações de implementação para o programador mal intencionado, aqui a fragmentação da plataforma na verdade é uma forma de protecção, pois cada telemóvel e versão de Android possui uma forma própria para obtenção de tais permissões (estamos a falar de aplicações obterem permissões Root da mesma forma que as aplicações para instalar Root funcionam, ou seja, sem intermédio da aplicação SuperUser pois aqui o utilizador controla o acesso).
O ponto que joga a favor dos exploiters é que a maioria do código para obtenção de root está disponível livremente na Internet, isto faz com que qualquer programador avançado tenha ferramentas fáceis para tirar partido disso para grupos de dispositivos pré-seleccionados. Uma ferramenta deste tipo de ataque genérico em Android é virtualmente impossível sendo que existem outras restrições que variam muito de fabricante para fabricante (NAND Locked, partições diferentes, versões diferentes de Android, diferentes arquitecturas exploráveis (ARMv6, ARMv7, …)).
Na verdade, neste ponto a plataforma iOS é bem mais vulnerável a ataques, falando de um ponto de vista tecnológico e sem contar com a filtragem que é feita nos repositórios de aplicações de cada um, uma vez que têm um leque limitado e uniforme de dispositivos cujas vulnerabilidades sendo conhecidas aplicam-se logo de imediato a uma grande fatia dos dispositivos.
A filtragem da App Store da Apple funciona como uma primeira linha de defesa contra este tipo de aplicações que é algo que também falha em Android, o que exige um cuidado reforçado na escolha de aplicações a instalar.
Por vezes é um conjunto de factores que no seu todo levam a que uma informação que não era suposto esteja disponível de forma que não deveria, como é o caso do Widget de meteorologia que vem pré-instalado em vários HTC e Samsung que dado à sua má programação publicita a localização do utilizador a nível de sistema e deixa essa informação de leitura para todas as aplicações, tal como demonstrei aqui.
Um outro exemplo prende-se com a manipulação errada de permissões em Android, aqui é preciso ter em conta mais uma vez que o erro está na ROM e na marca que a fez, e não no Android em geral.
Por exemplo em vários dispositivos HTC (incluindo o Nexus One), Motorola e Samsung existem falhas de sistema que permitem ler e tirar partido de certas funcionalidades de sistema que não deveriam acontecer dada a especificação do sistema de permissões e que permitem a leitura de SMSs, gravação de chamadas e captura de imagem:
Conclusão (resumida)
Note-se que estes 2 últimos exemplos são de extravio de informação de certas partes do sistema, a integralidade de informação de aplicações não foi comprometida. Estes e outros exemplos demonstram claramente que a não ser que a aplicação tenha alguma má prática de programação, qualquer dispositivo que passe os testes de compatibilidade da Google e sem contar com obtenção de permissões Root não permite a obtenção de dados privados de outra aplicação.
Quando há injecção de código, seria apenas possível com recurso a uma metodologia de rootkit, e para tal isso implicaria a substituição dos ficheiros DEX que constituem o Bytecode do Dalvik VM de uma aplicação. Para começar esta tarefa é bastante complexa, e requereria mais uma vez a obtenção de permissões Root para ser possível substituir ficheiros de outras aplicações.
Tirando esse caso não há registo de qualquer tipo de injecção de código em aplicações, muito menos com recurso a ficheiros JAR, só alguém que não percebe nada do sistema operativo poderia afirmar isso uma vez que o Bytecode de uma máquina virtual de Java convencional nada tem a ver com o Bytecode da DalvikVM, o próprio funcionamento estrutural é diferente, sendo que o Dalvik se assemelha muito mais a um sistema operativo comum. Vejamos pela descrição dos fundamentos aplicacionais de Android:
Android applications are written in the Java programming language. The Android SDK tools compile the code—along with any data and resource files—into an Android package, an archive file with an .apk suffix. All the code in a single .apk file is considered to be one application and is the file that Android-powered devices use to install the application. Once installed on a device, each Android application lives in its own security sandbox:
- The Android operating system is a multi-user Linux system in which each application is a different user.
- By default, the system assigns each application a unique Linux user ID (the ID is used only by the system and is unknown to the application). The system sets permissions for all the files in an application so that only the user ID assigned to that application can access them. • Each process has its own virtual machine (VM), so an application's code runs in isolation from other applications.
- By default, every application runs in its own Linux process. Android starts the process when any of the application's components need to be executed, then shuts down the process when it's no longer needed or when the system must recover memory for other applications. In this way, the Android system implements the principle of least privilege. That is, each application, by default, has access only to the components that it requires to do its work and no more. This creates a very secure environment in which an application cannot access parts of the system for which it is not given permission.
O próprio sistema visual de Android segue a mesma filosofia e que uma aplicação não pode interagir com o espaço de desenho de outra (citando Dianne Hackborn – lead-programmer do sistema visual de Android):
“Android had a number of very different original design goals than iOS did. A key goal of Android was to provide an open application platform, using application sandboxes to create a much more secure environment that doesn’t rely on a central authority to verify that applications do what they claim.
To achieve this, it uses Linux process isolation and user IDs to prevent each application from being able to access the system or other application in ways that are not controlled and secure.
This is very different from iOS’s original design constraints, which remember didn’t allow any third party applications at all.
An important part of achieving this security is having a way for (EDIT: It has been pointed out to me that iOS does in fact use multiple windows and multiple GL contexts. Lesson to me, just don't talk about anything I haven't directly verified. 🙂
That still doesn't change things for Android, though, where as I mention later we simply did not have hardware and drivers that could do multiple GL contexts until fairly recently.) individual UI elements to share the screen in a secure way. This is why there are windows on Android. The status bar and its notification shade are windows owned and drawn by the system. These are separate from the application’s window, so the application can not touch anything about the status bar, such as to scrape the text of SMS messages as they are displayed there. Likewise the soft keyboard is a separate window, owned by a separate application, and it and the application can only interact with each other through a well defined and controlled interface. (This is also why Android can safely support third party input methods.)”
Pedro Veloso é Licenciado em Ciências da Computação na Universidade do Minho e programador na empresa Emerge IT , uma empresa com actividade na área das Tecnologias da Informação e Comunicação (TIC), especializada na prestação de serviços e comercialização de soluções tecnológicas adaptadas a organizações, no desenvolvimento de soluções em Android, entre outros. É também membro core da equipa do androidPT onde participa activamente.
Este artigo tem mais de um ano
Artigo mesmo muito interessante. Nota-se que é de alguém que programa nestes dispositivos e pode ser muito útil para quem deseja entrar nesse mundo.
Onde está o botão +1?!?!?! 😛
Eu bem concordei contigo quando disse que não era tão linear 😛
Parabéns pelo artigo!
Excelente artigo, parabéns!
Estamos há mercê dos bites e bytes!
O iOS tb usa sandboxes e permissões para as aplicações. A diferença está na proibição de partilha de informação entre aplicações (filosofia de segurança).
A estrutura do iOS sempre permitiu aplicações de terceiros, multitasking, etc; é baseado no MacOS X, e estão lá quase todas as tecnologias que se encontram no Mac, o seu subsistema gráfico permite desde o início desenhar cada elemento no seu próprio espaço.
A Apple, no entanto, vedou o acesso a várias funções, para poder gerir melhor os recursos e por questões de segurança… mas tal como para o multitasking (e outros), nada impede que mais funções sejam disponibilizadas.
Dessa fora consegue também controlar determinados recursos que podem ser usados para outra fins.
E cada vez mais tem de haver uma política de responsabilidade das empresas que tutelam os serviços, pois já foi visto que é impossível imputar responsabilidades a quem pisa o risco.
Muitos parabens pelo artigo. Sou um leigo nestes assuntos e finalmente leio um artigo deste genero do inicio ao fim e consigo perceber a quase totalidade da informacao. Muito obrigado.
EXCELENTE ARTIGO
Excelente artigo! Vou partilhar!
Não posso avaliar da qualidade técnica do artigo pois não sou especialista neste sistema, mas a julgar pelos comentários que entretanto estão publicados a qualidade da informação não pode ser posta em causa.
Assim, gostaria de saber em termos muito simples se existe alguma maneira de proteger o meu Samsung Note e quais o perigos que devo evitar na sua utilização.
Como sou do tempo do MS-DOS, Windows 3.0, Basic etc… tento acompanhar estes novos tempos mas enfim as limitações são algumas.Obrigado e Boas Festas
Isso só por si dava mais um artigo. Resumidamente, e dentro daquilo que é tido competência do utilizador em Android, o melhor método (embora não infalível claro) é sempre ter alguma atenção ao instalar aplicações. Preferir os Programadores Principais (aqueles que têm um logotipo azul em frente ao nome, como este por exemplo : https://market.android.com/details?id=com.gameloft.android.ANMP.GloftA6HP ), e ler sempre sucintamente as permissões da aplicação. A parte de ler as permissões nem sempre é fácil porque por vezes existem permissões que são demasiado genéricas e na descrição não é dito exactamente o porquê do seu uso. De qualquer forma, número de downloads, rating e comentários iniciais também são uma boa forma de despistar potenciais problemas.
No que diz respeito a problemas da ROM, aí já é mais complicado, só mesmo um utilizador mais técnico que esteja ciente das mesmas é que se consegue proteger. No caso do Note, ele é afectado por este problema : http://forum.xda-developers.com/showthread.php?t=1342343 , mas felizmente tem uma solução simples ;).
Óptimo! Deu para aprender umas coisas 🙂
Um tipo de malware que tem atacado o Android Market – apps, disfarçadas de jogos conhecidos gratuitos, que fazem chamadas para números de valor acrescentado.
Quando essas apps foram detectadas (no caso, pela Lookout e pela Avast, que comunicaram à Google) e retiradas do Android Market, continuaram disponíveis em cerca de cinco markets “não oficiais”.
O autor dessas app (Miriada Production) indica na secção das “Rules” que a app cobra dinheiro – só que ninguém lê as rules.
https://blog.avast.com/2011/12/13/android-malware-in-the-open-marketplace/
Resumindo, nem todo o malware consiste em “uma aplicação ler dados e mesmo injectar código para outra aplicação em Android”, embora seja para aí que os olhos se voltam.
Isso está um pouco offtopic.
😉
Tens toda a razão. O artigo é focado apenas no “Isolamento e segurança aplicacional em Android”, o tema Segurança em Android é bem mais abrangente.
Aprendi mesmo muito! Obrigado!
Boa tarde ,
Caro Pedro Veloso , com os meus cumprimentos , agradeço a forma simples e directa de todo o artigo , mesmo para quem não é programador o mesmo está explicito Q.B .
Não queria deixar de agradecer o teu trabalho de muito valor que tens feito na XDA , proporcionando aos utilizadores ROMs optimizadas .
Sei que estás a actualizar diariamente o Kernel do Ice Cream , aconselhas já uma aventura com o Galaxy 2 , ou é ainda muito cedo ?
Mais uma vez muito obrigado pela tua contribuição a esta cada vez maior comunidade , fico muito contente de verificar que temos um programador de ponta que qualquer dia está a ser convidado pela Google , um bom Natal para ti e tua família , e um Ano Novo cheio de prosperidades .
Aceita os meus sinceros cumprimentos
Serva
Interessante artigo. Incompleto, mas interessante.
apenas um reparo iOS tem mais de “unix” que Android.
já windows phone não.
O artigo é interessante mas devo acrescentar o seguinte, o DalvikVM é um compilador JIT (Just-in-Time) é o equivalente em .net ao CLR.
Ou seja, o DalvikVM está para o Java como o .NET está para o CLR. E como qualquer compilador JIT esta sujeito a code injection.
Foi um comentário pertinente, obrigado ;). Segundo a documentação mais técnica de Jit na Dalvik VM é dito que :”Per-process translation caches (sharing only within security sandboxes)”, mas no entanto existem ferramentas para profiling e debug do Jit, geralmente basta colocar um “dalvik.vm.jit.profile = true” no ficheiro /data/local.prop para que tais funcionalidades estejam disponíveis. Essa facilidade está presente para auxilio dos programadores de modo a optimização das aplicação, embora nunca tenha testado em teoria será possível tirar partido disso para conseguir fazer algum tipo de code injection malicioso.
Esta talk é muito interessante para quem quiser aprofundar: http://www.google.com/events/io/2010/sessions/jit-compiler-androids-dalvik-vm.html
Excelente artigo.
Boa noite ,
Caro @Mário , aonde é que leste no artigo que o Windows phone tinha alguma coisa a ver com o Unix , toda a gente sabe que não tem , concordo contigo quando dizes que o IOS tem mais base Unix que o Android e a explicação está no Link abaixo , mas atenção que a pouco tempo como se demonstra no Link o Mac OSX era uma derivação de BSD , e só mais tarde é que passou a ser um SO unix certificado :
http://pt.wikipedia.org/wiki/Mac_OS_X
Este Link , apresenta o inicio do Linux que se baseou no Minix um pequeno SO baseado em Unix e que Linus Torvalds se limitou a melhorar , mas atenção que hoje as coisas esta~ao bem diferentes e a base Unix de estabilidade está lá toda aqui fica o segundo Link :
http://pt.wikipedia.org/wiki/Linux
Aceitem os meus sinceros cumprimentos
Serva
“mas atenção que a pouco tempo como se demonstra no Link o Mac OSX era uma derivação de BSD , e só mais tarde é que passou a ser um SO unix certificado”
O facto de só ter certificação UNIX na 3 últimas versões, tem muito pouca relevância para o assunto; a estrutura/base e tecnologias não necessitaram de mudar para ter essa certificação. A certificação paga-se e vem com certas obrigações… apenas serve de garantia para certas instituições que qualquer código para UNIX não terá problemas em ser compilado no Mac.
Excelente artigo.
Excelente artigo!
É bom ler artigos destes no pplware! 🙂
Muito bom este artigo, parabéns!!
Só tenho uma pergunta, tem alguma maneira de nós mesmos testar os aplicativos para ver se tem alguma destas vulnerabilidades?
mto bom
Artigo bom, as incompleto.
Devo adicionar o seguinte o Android é uma alteração ao OS Linux, e a forma como ele faz o isolamento é atraves de permissões em directorias. O que quer dizer que existe um utilizador de root ou mesmo um utilizador super “poderes”, isto torna muito “fácil” (comparado com outras plataformas) um utilizador mal intencionado fazer User Impersonation.
Muito bom artigo!
É por isso que só considero relevante no mundo Mobile o Windows Phone e em menor escala o iOS.
Segurança acima de tudo.