Register now for Android Dev Summit 2019!

Dicas de segurança

O Android inclui recursos de segurança integrados que reduzem significativamente a frequência e o impacto dos problemas de segurança de aplicativos. O sistema é projetado para que você possa compilar seus apps normalmente com permissões padrão do sistema e de arquivos e evitar decisões difíceis sobre a segurança.

Os principais recursos de segurança a seguir ajudam você a desenvolver apps seguros:

  • O sandbox de aplicativos do Android, que isola os dados e a execução do código do seu app de outros apps.
  • Uma estrutura de aplicativos com implementações robustas de funcionalidade comum de segurança, como criptografia, permissões e IPC (comunicação entre processos, na sigla em inglês) segura.
  • Tecnologias como ASLR, NX, ProPolice, safe_iop, OpenBSD dlmalloc, OpenBSD calloc e Linux mmap_min_addr para reduzir os riscos associados a erros comuns de gerenciamento de memória.
  • Um sistema de arquivos criptografado que pode ser ativado para proteger os dados em dispositivos perdidos ou roubados.
  • Permissões concedidas pelo usuário para restringir o acesso aos recursos do sistema e aos dados do usuário.
  • Permissões definidas por aplicativos para controlar os dados de cada aplicativo individualmente.

É importante se familiarizar com as práticas recomendadas para a segurança do Android apresentadas neste documento. Seguir estas práticas como hábitos gerais de criação de código reduzirá a probabilidade da introdução acidental de problemas de segurança que afetem seus usuários negativamente.

Armazenamento de dados

A preocupação de segurança mais comum para um aplicativo Android é se os dados salvos no dispositivo podem ser acessados por outros apps. Existem três maneiras fundamentais de salvar dados no dispositivo:

  • Armazenamento interno
  • Armazenamento externo
  • Provedores de conteúdo
Os parágrafos a seguir descrevem os problemas de segurança associados a cada abordagem.

Usar o armazenamento interno

Por padrão, os arquivos que você criar no armazenamento interno podem ser acessados apenas por seu app. O Android implementa essa proteção, e ela é suficiente para a maioria dos aplicativos.

De forma geral, evite os modos MODE_WORLD_WRITEABLE ou MODE_WORLD_READABLE para arquivos IPC, porque eles não permitem limitar o acesso de dados a aplicativos específicos, nem fornecem controle sobre o formato dos dados. Se quiser compartilhar seus dados com outros processos de apps, considere o uso de um provedor de conteúdo que ofereça permissões de leitura e gravação para outros apps e possa fazer concessões de permissões de acordo com cada caso.

Para fornecer mais proteção para dados confidenciais, é possível criptografar arquivos locais usando uma chave que não pode ser acessada diretamente pelo aplicativo. Por exemplo, é possível inserir uma chave em um KeyStore e protegê-la com uma senha de usuário que não esteja armazenada no dispositivo. Embora isso não proteja os dados contra uma violação de raiz que possa monitorar a inserção de senhas do usuário, essa abordagem pode oferecer proteção para um dispositivo perdido sem criptografia do sistema de arquivos.

Usar o armazenamento externo

Arquivos criados em um armazenamento externo, como cartões SD, podem ser lidos e gravados globalmente. Como o armazenamento externo pode ser removido pelo usuário e também modificado por qualquer aplicativo, não armazene informações confidenciais nele.

Você precisa validar as entradas ao manipular dados de armazenamento externo como faria com dados de fontes não confiáveis. Não armazene arquivos executáveis ou de classe no armazenamento externo antes do carregamento dinâmico. Se seu app recuperar arquivos executáveis de um armazenamento externo, eles precisam ser assinados e verificados criptograficamente antes do carregamento dinâmico.

Usar provedores de conteúdo

Provedores de conteúdo oferecem um mecanismo de armazenamento estruturado que pode ser limitado ao seu aplicativo ou exportado para permitir o acesso de outros aplicativos. Se você não pretende permitir que outros aplicativos acessem seu ContentProvider, marque-os como android:exported=false no manifesto. Caso contrário, defina o atributo android:exported como true para permitir que outros aplicativos acessem os dados armazenados.

Ao criar um ContentProvider que será exportado para o uso de outros aplicativos, você pode especificar uma só permissão de leitura e gravação ou permissões distintas de leitura e gravação. Limite suas permissões àquelas necessárias para realizar a tarefa em questão. Lembre-se de que geralmente é mais fácil adicionar permissões posteriormente para expor novos recursos do que removê-las e afetar os usuários existentes.

Se você estiver usando um provedor de conteúdo para compartilhar dados somente entre apenas seus próprios apps, é preferível usar o conjunto de atributos android:protectionLevel definido para a proteção signature. Permissões de assinatura não exigem a confirmação do usuário. Portanto, eles proporcionam uma experiência melhor para o usuário e um acesso mais controlado aos dados do provedor de conteúdo quando os aplicativos que acessam os dados são assinados com a mesma chave.

Provedores de conteúdo também podem fornecer um acesso mais granular declarando o atributo android:grantUriPermissions e usando os sinalizadores FLAG_GRANT_READ_URI_PERMISSION e FLAG_GRANT_WRITE_URI_PERMISSION no objeto Intent que ativa o componente. O escopo dessas permissões pode ser mais limitado pelo elemento <grant-uri-permission>.

Ao acessar um provedor de conteúdo, use métodos de consulta parametrizada, como query(), update() e delete(), para evitar possíveis injeções de SQL de fontes não confiáveis. Observe que o uso de métodos parametrizados não é suficiente se o argumento selection for incorporado ao concatenar dados do usuário antes de enviá-los ao método.

Não crie uma falsa sensação de segurança sobre a permissão de gravação. A permissão de gravação permite instruções SQL que possibilitam que alguns dados sejam confirmados usando cláusulas WHERE criativas e analisando os resultados. Por exemplo, um invasor pode verificar a presença de um número de telefone específico em um registro de chamadas ao modificar uma linha apenas se esse número já existir. Se os dados do provedor de conteúdo tiverem uma estrutura previsível, a permissão de gravação pode equivaler a uma permissão de leitura e gravação.

Uso de permissões

Como o Android isola os aplicativos uns dos outros, eles precisam compartilhar recursos e dados de forma explícita. Isso é feito ao declarar as permissões necessárias para recursos não fornecidos pelo sandbox básico, incluindo o acesso a recursos do dispositivo, como a câmera.

Solicitação de permissões

É preciso minimizar o número de permissões solicitadas pelos apps. Restringir o acesso a permissões confidenciais reduz o risco do uso indevido acidental dessas permissões, melhora a adoção dos usuários e torna seu app menos vulnerável a invasores. Em geral, se uma permissão não é necessária para o funcionamento do seu aplicativo, você não deve solicitá-la. Se um recurso for indispensável para o app, indique isso usando um elemento <uses-feature> no arquivo de manifesto.

Se for possível projetar seu aplicativo de forma que não exija permissões, essa é a abordagem preferencial. Por exemplo, em vez de solicitar o acesso a informações do dispositivo para criar um identificador exclusivo, crie um GUID para seu aplicativo (consulte a seção sobre o Gerenciamento dos dados do usuário). Ou, em vez de usar um armazenamento externo (que exige permissão), armazene dados no armazenamento interno.

Além de solicitar permissões, seu aplicativo pode usar o elemento <permission> para proteger o IPC que apresenta riscos de segurança e é exposto a outros aplicativos, como um ContentProvider. Em geral, recomendamos o uso de controles de acesso além de permissões confirmadas pelo usuário sempre que possível, porque as permissões podem ser confusas para os usuários. Por exemplo, considere o uso do nível de proteção de assinatura em permissões para comunicação de IPC entre aplicativos fornecidos por um só desenvolvedor.

Não vaze dados protegidos por permissões. Isso ocorre quando seu app expõe dados pela IPC que está disponível apenas porque seu app tem permissão para acessar esses dados. Os clientes da interface IPC do seu app podem não ter as mesmas permissões de acesso a dados. Mais detalhes sobre a frequência e os possíveis efeitos desse problema aparecem no trabalho de pesquisa Re-Delegação de permissão: ataques e defesas (link em inglês), publicado na USENIX.

Criação de permissões

Em geral, tente definir o menor número possível de permissões e atender aos seus requisitos de segurança. Criar uma nova permissão é relativamente incomum para a maioria dos aplicativos, porque as permissões definidas pelo sistema englobam muitas situações. Quando apropriado, realize verificações de acesso usando permissões existentes.

Se for preciso criar uma nova permissão, considere se sua tarefa pode ser executada com um nível de proteção de assinatura. Permissões de assinatura são transparentes para o usuário e só permitem o acesso de aplicativos assinados pelo mesmo desenvolvedor do aplicativo que executa a verificação de permissão. Se a nova permissão ainda for necessária, ela será declarada no manifesto do app usando o elemento <permission>. Apps que queiram usar a nova permissão podem referenciá-la adicionando um elemento <uses-permission> nos respectivos arquivos de manifesto. Também é possível adicionar permissões de modo dinâmico usando o método addPermission().

Se você criar uma permissão com o nível de proteção "perigoso", considere as seguintes complexidades:

  • A permissão precisa ter uma string que expresse, de forma concisa, a decisão de segurança que o usuário precisa tomar.
  • A string de permissão precisa ser localizada para vários idiomas diferentes.
  • Os usuários podem escolher não instalar um aplicativo porque uma permissão parece ser confusa ou arriscada.
  • Aplicativos podem solicitar a permissão quando o criador dela não tiver sido instalado.

Cada uma dessas situações apresenta um desafio não técnico significativo para você, como desenvolvedor, além de confundir seus usuários. Por esse motivo, não incentivamos o uso do nível de permissão perigoso.

Uso da rede

Transações de rede são inerentemente arriscadas para segurança, porque envolvem a transmissão de dados potencialmente privados para o usuário. As pessoas estão cada vez mais conscientes das questões de privacidade de um dispositivo móvel, especialmente quando esse dispositivo executa transações de rede. Dessa forma, é muito importante que seu app implemente todas as práticas recomendadas para manter os dados do usuário protegidos a todo o momento.

Uso de rede IP

A rede do Android não é muito diferente de outros ambientes Linux. A principal consideração é garantir que os protocolos apropriados sejam usados para dados confidenciais, como o HttpsURLConnection para o tráfego da Web seguro. É recomendável usar HTTPS em vez de HTTP em qualquer local que esse protocolo seja compatível com o servidor, porque os dispositivos móveis frequentemente se conectam a redes que não são protegidas, como pontos de acesso Wi-Fi públicos.

A comunicação de nível de soquete criptografada e autenticada pode ser facilmente implementada usando a classe SSLSocket. Considerando a frequência com a qual os dispositivos Android se conectam a redes sem fio desprotegidas usando Wi-Fi, o uso da rede segura é fortemente encorajado para todos os aplicativos que se comunicam por rede.

Alguns aplicativos usam as portas de rede localhost para gerenciar IPC confidencial. Não recomendamos o uso dessa abordagem, porque essas interfaces podem ser acessadas por outros aplicativos do dispositivo. Em vez disso, use um mecanismo de IPC do Android no qual a autenticação seja possível, como um Service. Vincular a INADDR_ANY é pior do que usar um loopback, porque seu aplicativo poderá receber solicitações de qualquer lugar.

Não confie em dados transferidos por download de HTTP ou de outros protocolos não seguros. Isso inclui a validação de entradas no WebView e de qualquer resposta a intents emitidas por HTTP.

Uso da rede de telefonia

O protocolo SMS foi projetado principalmente para a comunicação entre usuários e não é adequado para a transferência de dados de aplicativos. Devido às limitações do SMS, é recomendável o uso do Google Cloud Messaging (GCM) e da rede IP para o envio de mensagens de dados de um servidor da Web para seu app em um dispositivo do usuário.

Esteja ciente de que o SMS não é criptografado ou fortemente autenticado na rede ou no dispositivo. Em particular, qualquer receptor de destinatário de SMS deve esperar que um usuário mal-intencionado possa ter enviado o SMS para seu aplicativo. Não utilize dados SMS não autenticados para executar comandos essenciais. Além disso, esteja ciente de que o SMS pode estar sujeito a spoofing e/ou a interceptação na rede. No próprio dispositivo Android, as mensagens SMS são transmitidas como intents de transmissão, portanto, elas podem ser lidas ou capturadas por outros aplicativos que tenham a permissão READ_SMS.

Validação de entradas

A validação insuficiente de entradas é um dos problemas de segurança mais comuns que afeta os aplicativos, independentemente da plataforma em que são executados. O Android tem medidas no nível da plataforma para reduzir a exposição de aplicativos a problemas de validação de entradas, e você precisa usar esses recursos sempre que possível. Observe também que a seleção de linguagens com segurança de tipo tende a reduzir a probabilidade de problemas de validação de entradas.

Se você estiver usando o código nativo, todos os dados lidos dos arquivos, recebidos pela rede ou recebidos por um IPC podem introduzir um problema de segurança. Os problemas mais comuns são sobrecargas de buffer, uso após a liberação e erros off-by-one. O Android oferece várias tecnologias, como ASLR e DEP, que reduzem a capacidade de exploração desses erros, mas não resolvem o problema subjacente. Essas vulnerabilidades podem ser evitadas com a manipulação cuidadosa de ponteiros e o gerenciamento de buffers.

Linguagens dinâmicas baseadas em strings, como JavaScript e SQL, também estão sujeitas a problemas de validação de entradas devido a caracteres com escape e à injeção de script.

Se você estiver usando dados em consultas enviadas a um banco de dados SQL ou um provedor de conteúdo, a injeção de SQL poderá ser um problema. A melhor defesa é o uso de consultas parametrizadas, conforme discutido na seção acima sobre provedores de conteúdo. A limitação de permissões para somente leitura ou somente gravação também pode reduzir o risco relacionado à injeção de SQL.

Se você não puder usar os recursos de segurança acima, use formatos de dados bem estruturados e verifique se os dados seguem o formato esperado. Embora a inclusão de caracteres na lista de proibições ou a substituição de caracteres possam ser estratégias eficazes, essas técnicas tendem ao erro na prática e precisam ser evitadas sempre que possível.

Gerenciamento de dados do usuário

Em geral, a melhor abordagem para a segurança dos dados do usuário é minimizar o uso de APIs que acessam dados confidenciais ou pessoais do usuário. Se você tiver acesso aos dados do usuário e puder evitar o armazenamento ou a transmissão dessas informações, faça isso. Considere se existe uma maneira de implementar a lógica do seu aplicativo usando um hash ou um formato não reversivo dos dados. Por exemplo, seu aplicativo pode usar o hash de um endereço de e-mail como uma chave primária para evitar a transmissão ou o armazenamento do endereço de e-mail. Isso reduz as chances de exposição acidental dos dados e de tentativas de exploração do seu aplicativo por parte de invasores.

Se seu aplicativo acessar informações pessoais como senhas ou nomes de usuário, lembre-se de que algumas jurisdições podem exigir que você forneça uma política de privacidade explicando seu uso e armazenamento desses dados. Portanto, o uso das práticas recomendadas de segurança para minimizar o acesso aos dados do usuário também pode simplificar o processo de compliance.

Considere também se seu aplicativo pode estar expondo acidentalmente informações pessoais para outras partes, como componentes de terceiros para publicidade ou serviços de terceiros usados por seu aplicativo. Se não souber porque um componente ou serviço precisa de informações pessoais, não as forneça. Em geral, a redução do acesso a informações pessoais por parte do seu aplicativo reduzirá o potencial para problemas nessa área.

Se o acesso a dados confidenciais for necessário, avalie se essas informações precisam ser transmitidas a um servidor ou se a operação pode ser executada no cliente. Considere executar qualquer código usando dados confidenciais no cliente para evitar a transmissão de dados do usuário. Além disso, evite ao máximo a exposição acidental de dados do usuário a outros aplicativos do dispositivo com um IPC muito permissivo, arquivos graváveis globalmente ou soquetes de rede. A IPC excessivamente permissiva é um caso especial de vazamento de dados protegidos por permissão, discutido na seção Solicitação de permissões.

Se um GUID for necessário, crie um número grande e exclusivo e armazene-o. Não use identificadores de telefone, como o número de telefone ou o IMEI, que podem ser associados a informações pessoais. Esse tópico é discutido em mais detalhes no Blog de desenvolvedores do Android.

Tenha cuidado ao escrever em registros no dispositivo. No Android, os registros são um recurso compartilhado e são disponibilizados para um aplicativo com a permissão READ_LOGS. Mesmo que os dados de registro do telefone sejam temporários e apagados após a reinicialização, o registro inapropriado de informações do usuário pode acabar vazando dados do usuário para outros aplicativos. Além de não registrar PII, os apps de produção precisam limitar o uso de registro. Para implementar isso com facilidade, use sinalizadores de depuração e classes de Log personalizadas com níveis de registro facilmente configuráveis.

Uso do WebView

Como o WebView consome conteúdo Web que pode incluir HTML e JavaScript, o uso impróprio pode introduzir problemas comuns de segurança da Web como cross-site-scripting (injeção de JavaScript). O Android inclui diversos mecanismos para reduzir o escopo desses possíveis problemas ao limitar a capacidade do WebView à funcionalidade mínima exigida pelo seu aplicativo.

Se seu aplicativo não usar JavaScript diretamente em um WebView, não chame setJavaScriptEnabled(). Alguns códigos de exemplo usam esse método, que pode ser reutilizado no aplicativo de produção. Portanto, remova a chamada do método se ela não for necessária. Por padrão, o WebView não executa JavaScript, logo, cross-site-scripting não é possível.

Use addJavaScriptInterface() com um cuidado, porque ele permite que o JavaScript invoque operações normalmente reservadas a aplicativos Android. Se você usá-lo, exponha addJavaScriptInterface() apenas para páginas da Web em que todas as entradas sejam confiáveis. Se entradas não confiáveis forem permitidas, um JavaScript não confiável poderá invocar métodos do Android no seu app. Em geral, recomendamos expor addJavaScriptInterface() apenas para o JavaScript contido no APK do seu aplicativo.

Se seu aplicativo acessar dados confidenciais com um WebView, use o método clearCache() para excluir arquivos armazenados localmente. Você também pode usar cabeçalhos do lado do servidor, como o no-cache, para indicar que um aplicativo não deve armazenar em cache conteúdos específicos.

Dispositivos que executam plataformas mais antigas que o Android 4.4 (API de nível 19) usam uma versão do webkit que tem diversos problemas de segurança. Como solução alternativa, se seu aplicativo estiver sendo executado nesses dispositivos, ele precisa confirmar que os objetos WebView exibem apenas conteúdo confiável. Para garantir que seu app não seja exposto a possíveis vulnerabilidades no SSL, use o objeto de segurança atualizável Provider, conforme descrito em Atualizar seu provedor de segurança para proteger-se contra explorações de SSL. Se seu aplicativo precisar renderizar conteúdo da Web aberta, considere fornecer seu próprio renderizador para mantê-lo atualizado com os últimos patches.

Gerenciamento de credenciais

Para tornar os ataques de phishing mais evidentes e reduzir a probabilidade de sucesso deles, minimize a frequência de solicitações de credenciais do usuário. Em vez disso, use um token de autorização e atualize-o.

Sempre que possível, não armazene nomes de usuário e senhas no dispositivo. Em vez disso, realize a autenticação inicial usando o nome de usuário e a senha fornecidos pelo usuário e então use um token de autorização de curta duração específico para serviços.

Serviços acessíveis a vários aplicativos precisam ser acessados usando AccountManager. Se possível, use a classe AccountManager para invocar um serviço baseado na nuvem e não armazene senhas no dispositivo.

Depois de usar AccountManager para recuperar um Account, use CREATOR antes de passar qualquer credencial para que você evite passar acidentalmente as credenciais para aplicativos errados.

Se as credenciais forem usadas apenas por aplicativos criados por você, será possível verificar o aplicativo que acessar o AccountManager usando checkSignature(). Como alternativa, se apenas um aplicativo usará a credencial, você pode usar um KeyStore para armazenamento.

Uso da criptografia

Além de oferecer isolamento de dados, compatibilidade com a criptografia para todo o sistema de arquivos e canais de comunicação seguros, o Android fornece diversos algoritmos para proteger dados usando a criptografia.

Em geral, você precisa saber quais provedores de segurança da Arquitetura de criptografia Java (JCA, na sigla em inglês) seu software usa. Tente usar o nível mais alto de implementação da estrutura pré-existente que seja compatível com seu caso de uso. Se aplicável, use os provedores fornecidos pelo Google no pedido especificado por ele. Se precisar recuperar um arquivo de um local conhecido de forma segura, um simples URI HTTPS pode ser adequado e não exige conhecimento de criptografia. Se precisar de um túnel seguro, considere usar HttpsURLConnection ou SSLSocket, em vez de criar seu próprio protocolo. Se você usa o SSLSocket, esteja ciente de que ele não executa a verificação do nome do host. Consulte Avisos sobre o uso direto do SSLSocket.

Se precisar implementar seu próprio protocolo, não implemente seus próprios algoritmos criptográficos. Use algoritmos criptográficos existentes, como os da implementação de AES ou RSA fornecida na classe Cipher. Além disso, siga estas práticas recomendadas:

  • Use AES de 256 bits para fins comerciais. Se ele não estiver disponível, use o AES de 128 bits.
  • Use chaves públicas de 224 ou 256 bits para criptografia de curva elíptica (EC, na sigla em inglês).
  • Saiba quando usar os modos de bloqueio CBC, CTR ou GCM.
  • Evite reutilizar o vetor de inicialização (IV, na sigla em inglês)/contador no modo CTR. Eles precisam ser criptograficamente aleatórios.
  • Ao usar criptografia, implemente a integridade usando o modo CBC ou CTR com uma das seguintes funções:
    • HMAC-SHA1
    • HMAC-SHA-256
    • HMAC-SHA-512
    • Modo GCM

Use um gerador de número aleatório seguro, SecureRandom, para inicializar qualquer chave criptográfica gerada pelo KeyGenerator. O uso de uma chave que não for gerada por um gerador de número aleatório seguro reduz significativamente a força do algoritmo e pode permitir ataques off-line.

Se você precisar armazenar uma chave para uso repetido, use um mecanismo como KeyStore que ofereça armazenamento de longo prazo e recuperação de chaves criptográficas.

Uso da comunicação entre processos

Alguns apps tentam implementar IPC usando técnicas tradicionais do Linux, como soquetes de rede e arquivos compartilhados. Em vez disso, use recursos do sistema Android para IPC, como Intent, Binder ou Messenger com um Service e BroadcastReceiver. Os mecanismos de IPC do Android permitem que você verifique a identidade do aplicativo que estiver se conectando à sua IPC e defina políticas de segurança para cada mecanismo de IPC.

Muitos dos elementos de segurança são compartilhados entre mecanismos de IPC. Se seu mecanismo de IPC não for destinado ao uso de outros aplicativos, defina o atributo android:exported como false no elemento de manifesto do componente, por exemplo, para o elemento <service>. Isso é útil para aplicativos que consistem de vários processos no mesmo UID, ou se você decidir posteriormente durante o desenvolvimento que não quer expor a funcionalidade como IPC, mas não quiser reprogramar o código.

Se sua IPC for acessada por outros aplicativos, você poderá aplicar uma política de segurança usando o elemento <permission>. Se a IPC estiver entre seus próprios aplicativos separados que foram assinados com a mesma chave, é preferível usar a permissão de nível signature no android:protectionLevel.

Uso de intents

Para atividades e broadcast receivers, os intents são o mecanismo preferido para IPC assíncrona no Android. Dependendo dos requisitos do seu aplicativo, você pode usar sendBroadcast(), sendOrderedBroadcast() ou um intent explícito para um componente de aplicativo específico. Por motivos de segurança, intents explícitos são preferidos.

Atenção: se você usa um intent para se vincular a um Service, garanta a segurança do seu app usando um intent explícito. O uso de um intent implícito para iniciar um serviço representa um risco de segurança, porque não é possível determinar qual serviço responderá ao intent e o usuário não poderá ver qual serviço será iniciado. Desde o Android 5.0 (API de nível 21), o sistema lança uma exceção ao chamar bindService() com um intent implícito.

Observe que transmissões ordenadas podem ser consumidas por um destinatário, portanto, elas podem não ser entregues para todos os aplicativos. Se você estiver enviando um intent que precise ser entregue para um destinatário específico, use um intent explícito que declare o destinatário com nameintent.

Os remetentes de um intent podem verificar se o destinatário tem uma permissão que especifique uma permissão não nula com a chamada do método. Apenas aplicativos com essa permissão receberão o intent. Se for possível que os dados em um intent de transmissão sejam confidenciais, considere aplicar uma permissão para garantir que aplicativos mal-intencionados não possam se registrar para receber essas mensagens sem as permissões apropriadas. Nessas condições, considere também invocar o destinatário diretamente, em vez de gerar uma transmissão.

Observação: os filtros de intent não podem ser considerados um recurso de segurança. Componentes podem ser invocados com intents explícitos e podem não ter dados em conformidade com o filtro de intent. Para confirmar se ele está formatado corretamente para o destinatário, o serviço ou a atividade que foi invocada, execute a validação de entradas no seu destinatário de intent.

Uso de serviços

Um Service é frequentemente usado para fornecer recursos para o uso de outros aplicativos. Cada classe de serviço precisa ter um declaração <service> correspondente no arquivo de manifesto.

Por padrão, os serviços não são exportados e não podem ser invocados por qualquer outro aplicativo. No entanto, se você adicionar filtros de intent na declaração de serviço, ele será exportado por padrão. É melhor declarar explicitamente o atributo android:exported para ter certeza de que ele se comportará da maneira desejada. Os serviços também podem ser protegidos usando o atributo android:permission. Ao fazer isso, outros aplicativos precisam declarar um elemento <uses-permission> correspondente nos próprios manifestos para poderem iniciar, interromper ou vincular o serviço.

Observação: se seu app for voltado para o Android 5.0 (API de nível 21) ou posterior, use o JobScheduler para executar serviços em segundo plano. Para mais informações sobre o JobScheduler, consulte a API-reference documentation.

Um serviço pode proteger chamadas de IPC individuais dentro dele com permissões ao chamar checkCallingPermission() antes de executar a implementação dessa chamada. Use as permissões declarativas no manifesto, porque elas são menos propensas a lapsos.

Atenção: não confunda permissões de cliente e servidor; certifique-se de que o app chamado tenha as permissões apropriadas e verifique se você concede as mesmas permissões ao app de chamada.

Uso de interfaces binder e messenger

O uso de Binder ou Messenger é o mecanismo preferencial para a IPC de estilo RPC no Android. Eles proporcionam uma interface bem definida que possibilita a autenticação mútua dos pontos de extremidade, se necessário.

Você precisa desenvolver suas interfaces de app de forma que não exijam verificações de permissões específicas de interface. Os objetos Binder e Messenger não são declarados no manifesto do aplicativo e, dessa forma, não é possível aplicar permissões declarativas diretamente neles. Eles geralmente herdam as permissões declaradas no manifesto do aplicativo para o Service ou a Activity em que são implementados. Se você estiver criando uma interface que exija autenticação e/ou controles de acesso, esses controles precisam ser explicitamente adicionados como código na interface Binder ou Messenger.

Se você estiver fornecendo uma interface que exija controles de acesso, use checkCallingPermission() para verificar se o autor da chamada tem uma permissão obrigatória. Isso é especialmente importante antes de acessar um serviço em nome do chamador, porque a identidade do seu aplicativo é passada para outras interfaces. Se você estiver invocando uma interface fornecida por um Service, a invocação bindService() poderá falhar se você não tiver permissão para acessar o serviço em questão. Se você estiver chamando uma interface fornecida localmente por seu próprio aplicativo, pode ser útil usar o método clearCallingIdentity(), que mascara as permissões do chamador em relação às permissões do app, para satisfazer as verificações internas de segurança. É possível restaurar as permissões do chamador posteriormente usando o método restoreCallingIdentity().

Para mais informações sobre como executar IPC com um serviço, consulte Serviços vinculados.

Uso de broadcast receivers

Um BroadcastReceiver gerencia as solicitações assíncronas iniciadas por um Intent.

Por padrão, os destinatários são exportados e podem ser invocados por qualquer outro aplicativo. Se seu BroadcastReceiver for usado por outros aplicativos, pode ser recomendável aplicar permissões de segurança para destinatários usando o elemento <receiver> no manifesto do aplicativo. Isso impede que aplicativos que não tenham as permissões apropriadas enviem um intent ao BroadcastReceiver.

Carregamento dinâmico de código

Não é recomendado fazer o carregamento de código fora do APK do seu aplicativo. Isso pode aumentar significativamente a probabilidade de comprometimento do aplicativo por injeção ou violação de código. Essa abordagem também adiciona complexidade ao gerenciamento de versões e ao teste de aplicativos. Por fim, ela também pode impossibilitar a verificação do comportamento de um aplicativo, portanto, pode ser proibida em alguns ambientes.

Se seu aplicativo carregar código dinamicamente, o mais importante a se lembrar é que ele é executado com as mesmas permissões de segurança que o APK do aplicativo. O usuário tomou a decisão de instalar seu aplicativo com base na sua identidade e espera que todas as execuções de códigos sejam realizadas no aplicativo, inclusive códigos carregados dinamicamente.

O principal risco de segurança associado ao carregamento dinâmico é que o código precisa ser originado em uma fonte verificável. Se os módulos forem incluídos diretamente no seu APK, eles não poderão ser modificados por outros aplicativos. Isso é válido independentemente de o código ser uma biblioteca nativa ou uma classe carregada usando DexClassLoader. Muitos aplicativos tentam carregar códigos de locais inseguros, como códigos transferidos por download da rede por meio de protocolos não criptografados ou de locais globalmente graváveis, como um armazenamento externo. Esses locais poderiam permitir que um usuário da rede modificasse o conteúdo em trânsito ou que outro aplicativo no dispositivo de um usuário modificasse o conteúdo no dispositivo.

Segurança em uma máquina virtual

O Dalvik é a VM (máquina virtual) de tempo de execução do Android. O Dalvik foi criado especificamente para o Android, mas muitas das preocupações relacionadas com a segurança do código em outras máquinas virtuais também se aplicam ao Android. Em geral, não é necessário se preocupar com problemas de segurança relacionados à máquina virtual. Seu aplicativo é executado em um ambiente de sandbox seguro, portanto, outros processos no sistema não podem acessar seu código ou seus dados privados.

Se tiver interesse em saber mais sobre segurança de máquinas virtuais, familiarize-se com a literatura existente sobre o assunto. Dois dos recursos mais populares são:

Este documento se concentra em áreas específicas do Android ou que diferem de outros ambientes de VM. Para desenvolvedores que têm experiência em programação de VMs em outros ambientes, existem duas questões amplas que podem ser diferentes na programação de apps para Android:

  • Algumas máquinas virtuais, como a JVM ou o tempo de execução .net, funcionam como limites de segurança, isolando o código dos recursos subjacentes do sistema operacional. No Android, a VM Dalvik não é um limite de segurança. O sandbox do aplicativo é implementado no nível do SO, assim o Dalvik pode ser interoperado com o código nativo no mesmo aplicativo, sem limitações de segurança.
  • Considerando o armazenamento limitado dos dispositivos móveis, é comum que os desenvolvedores queiram criar aplicativos modulares e usar o carregamento dinâmico de classes. Ao fazer isso, considere a fonte em que você recupera a lógica do seu aplicativo e onde você a armazena localmente. Não use o carregamento dinâmico de classes de fontes que não sejam verificadas, como fontes de redes não protegidas ou armazenamentos externos, porque o código pode ser modificado para incluir comportamentos mal-intencionados.

Segurança no código nativo

Em geral, recomendamos o uso do Android SDK para o desenvolvimento de aplicativos, em vez de usar o código nativo com o Android NDK. Aplicativos criados com código nativo são mais complexos, menos portáteis e mais propensos a incluir erros comuns de corrupção de memória, como sobrecargas de buffer.

O Android é criado com o kernel do Linux e estar familiarizado com as práticas recomendadas para a segurança de desenvolvimento do Linux é especialmente útil se você estiver usando código nativo. As práticas de segurança do Linux estão fora do escopo deste documento, mas um dos recursos mais usados é Secure Programming HOWTO - Creating Secure Software.

Uma diferença importante entre o Android e a maioria dos ambientes Linux é o sandbox de aplicativos. No Android, todos os aplicativos são executados no sandbox de aplicativos, incluindo os criados com código nativo. No nível mais básico, uma boa maneira de considerar esse cenário para desenvolvedores com experiência em Linux é saber que cada aplicativo recebe um UID exclusivo com permissões muito limitadas. Isso é discutido em mais detalhes na Visão geral de segurança do Android e você precisa estar familiarizado com as permissões do aplicativo, mesmo que esteja usando o código nativo.