A maioria dos desenvolvedores de aplicativos integrará algumas bibliotecas de terceiros em seus aplicativos. Se é para acessar um serviço, como Dropbox ou YouTube, ou para falhas de registro. O número de bibliotecas e serviços de terceiros é impressionante. A maioria dessas bibliotecas e serviços é integrada de alguma maneira pela autenticação com o serviço, na maioria das vezes, isso acontece por meio de uma chave de API. Por motivos de segurança, os serviços geralmente geram uma chave pública e privada, geralmente também conhecida como chave secreta. Infelizmente, para se conectar aos serviços, essa chave privada deve ser usada para autenticar e, portanto, provavelmente fazer parte do aplicativo. Escusado será dizer que isso enfrenta um imenso problema de segurança. As chaves de API públicas e privadas podem ser extraídas dos APKs em questão de minutos e podem ser facilmente automatizadas.
Supondo que eu tenha algo parecido com isso, como posso proteger a chave secreta:
public class DropboxService {
private final static String APP_KEY = "jk433g34hg3";
private final static String APP_SECRET = "987dwdqwdqw90";
private final static AccessType ACCESS_TYPE = AccessType.DROPBOX;
// SOME MORE CODE HERE
}
Na sua opinião, qual é a melhor e mais segura maneira de armazenar a chave privada? Ofuscação, criptografia, o que você acha?
fonte
Respostas:
Como está, seu aplicativo compilado contém as cadeias de teclas, mas também os nomes constantes APP_KEY e APP_SECRET. Extrair chaves desse código de auto-documentação é trivial, por exemplo, com a ferramenta Android padrão dx.
Você pode aplicar o ProGuard. Ele deixará as cadeias de teclas intocadas, mas removerá os nomes das constantes. Ele também renomeará classes e métodos com nomes curtos e sem sentido, sempre que possível. A extração das chaves leva mais tempo, para descobrir qual sequência serve para qual finalidade.
Observe que a instalação do ProGuard não deve ser tão difícil quanto você teme. Para começar, você só precisa ativar o ProGuard, conforme documentado em project.properties. Se houver algum problema com as bibliotecas de terceiros, talvez seja necessário suprimir alguns avisos e / ou impedir que eles sejam ofuscados, em proguard-project.txt. Por exemplo:
Essa é uma abordagem de força bruta; você pode refinar essa configuração assim que o aplicativo processado funcionar.
Você pode ofuscar as strings manualmente no seu código, por exemplo, com uma codificação Base64 ou, de preferência, com algo mais complicado; talvez até código nativo. Um hacker precisará, então, fazer engenharia reversa estaticamente na sua codificação ou interceptar dinamicamente a decodificação no local apropriado.
Você pode aplicar um ofuscador comercial, como o irmão especializado do ProGuard, DexGuard . Além disso, ele pode criptografar / ofuscar as strings e classes para você. A extração das chaves leva ainda mais tempo e conhecimento.
Você pode executar partes do seu aplicativo em seu próprio servidor. Se você pode manter as chaves lá, elas são seguras.
No final, é uma troca econômica que você deve fazer: qual a importância das chaves, quanto tempo ou software você pode pagar, qual a sofisticação dos hackers que estão interessados nas chaves e quanto tempo eles desejam gastar, quanto vale um atraso antes que as chaves sejam invadidas, em que escala algum hacker bem-sucedido distribuirá as chaves, etc. Pequenas informações como chaves são mais difíceis de proteger do que aplicativos inteiros. Intrinsecamente, nada do lado do cliente é inquebrável, mas você certamente pode elevar a fasquia.
(Eu sou o desenvolvedor do ProGuard e DexGuard)
fonte
Poucas idéias, na minha opinião, apenas a primeira dá alguma garantia:
Mantenha seus segredos em algum servidor na Internet e, quando necessário, apenas pegue-os e use-os. Se o usuário estiver prestes a usar o dropbox, nada o impedirá de fazer uma solicitação ao seu site e obter sua chave secreta.
Coloque seus segredos no código jni, adicione algum código de variável para tornar suas bibliotecas maiores e mais difíceis de descompilar. Você também pode dividir as chaves em poucas partes e mantê-las em vários lugares.
use ofuscador, também coloque código hash secreto e mais tarde unhash quando necessário.
Coloque sua chave secreta como os últimos pixels de uma imagem em ativos. Quando necessário, leia-o no seu código. Ofuscar seu código deve ajudar a ocultar o código que o lerá.
Se você quiser dar uma olhada rápida em como é fácil ler o código apk, então pegue o APKAnalyser:
http://developer.sonymobile.com/knowledge-base/tool-guides/analyse-your-apks-with-apkanalyser/
fonte
Outra abordagem é não ter o segredo no dispositivo em primeiro lugar! Consulte Técnicas de segurança da API móvel (especialmente a parte 3).
Usando a antiga tradição de indireção, compartilhe o segredo entre o terminal da API e um serviço de autenticação de aplicativos.
Quando seu cliente deseja fazer uma chamada de API , solicita que o serviço de autenticação de aplicativo o autentique (usando técnicas fortes de atestado remoto) e recebe um token de tempo limitado (geralmente JWT ) assinado pelo segredo.
O token é enviado com cada chamada da API em que o terminal pode verificar sua assinatura antes de agir na solicitação.
O segredo real nunca está presente no dispositivo; de fato, o aplicativo nunca tem idéia se é válido ou não, ele solicita autenticação e passa o token resultante. Como um bom benefício da indireção, se você quiser alterar o segredo, poderá fazê-lo sem exigir que os usuários atualizem seus aplicativos instalados.
Portanto, se você deseja proteger seu segredo, não tê-lo em seu aplicativo é um bom caminho.
fonte
Maneira velha não segura:
Siga três etapas simples para proteger a API / chave secreta ( resposta antiga )
Podemos usar o Gradle para proteger a chave da API ou a chave secreta.
1. gradle.properties (Propriedades do projeto): Crie variável com a chave.
2. build.gradle (Module: app): defina a variável em build.gradle para acessá-la em atividade ou fragmento. Adicione o código abaixo para buildTypes {}.
3. Acesse-o em Activity / Fragment pelo BuildConfig do aplicativo:
Atualização:
A solução acima é útil no projeto de código aberto para confirmar sobre o Git. (Obrigado a David Rawson e riyaz-ali pelo seu comentário).
De acordo com os comentários de Matthew e Pablo Cegarra, a maneira acima não é segura e o Decompiler permitirá que alguém veja o BuildConfig com nossas chaves secretas.
Solução:
Podemos usar o NDK para proteger as chaves da API. Podemos armazenar chaves na classe nativa C / C ++ e acessá-las em nossas classes Java.
Siga este blog para proteger as chaves da API usando NDK.
Um acompanhamento sobre como armazenar tokens com segurança no Android
fonte
gradle.properties
não deve ser verificado para Git por isso esta é uma forma de manter a fora segredo do código fonte comprometida, pelo menosapk
(será adicionada aoBuildConfig
arquivo gerado ), embora seja definitivamente uma boa idéia gerenciar diferentes chaves da API (por exemplo, em um projeto de código aberto)BuildConfig.java
arquivo terá a chave em forma de texto sem formatação. Isso não é melhor do que o que o OP já está fazendo.para aqueles caras que não vai esconder, bloqueie
ProGuard
o código. É um refator e alguns ofuscadores pagos estão inserindo alguns operadores bit a bit para recuperar ajk433g34hg3
String. Você pode aumentar de 5 a 15 minutos os hackers se trabalhar 3 dias :)A melhor maneira é mantê-lo como está, imho.
Mesmo se você armazenar no lado do servidor (seu PC), a chave poderá ser invadida e impressa. Talvez isso demore mais? De qualquer forma, é uma questão de alguns minutos ou algumas horas, na melhor das hipóteses.
Um usuário normal não descompilará seu código.
fonte
Uma solução possível é codificar os dados no seu aplicativo e usar a decodificação em tempo de execução (quando você deseja usar esses dados). Também recomendo usar progaurd para dificultar a leitura e a compreensão do código-fonte descompilado do seu aplicativo. por exemplo, coloquei uma chave codificada no aplicativo e usei um método de decodificação no meu aplicativo para decodificar minhas chaves secretas em tempo de execução:
O código fonte descompilado de um aplicativo programado é este:
Pelo menos é bastante complicado para mim. é dessa maneira que faço quando não tenho escolha, além de armazenar um valor no meu aplicativo. É claro que todos sabemos que não é o melhor caminho, mas funciona para mim.
Versão descompilada:
e você pode encontrar muitas classes de criptografia com uma pequena pesquisa no google.
fonte
Adicionando à solução @Manohar Reddy, o firebase Database ou o firebase RemoteConfig (com valor padrão Nulo) pode ser usado:
O que é diferente nesta solução?
fonte
Este exemplo possui vários aspectos diferentes. Mencionarei alguns pontos que acho que não foram explicitamente abordados em outro lugar.
Protegendo o segredo em trânsito
A primeira coisa a observar é que o acesso à API do dropbox usando o mecanismo de autenticação de aplicativos exige que você transmita sua chave e segredo. A conexão é HTTPS, o que significa que você não pode interceptar o tráfego sem conhecer o certificado TLS. Isso evita que uma pessoa intercepte e leia os pacotes em sua jornada do dispositivo móvel para o servidor. Para usuários normais, é realmente uma boa maneira de garantir a privacidade de seu tráfego.
O que não é bom é impedir que uma pessoa mal-intencionada baixe o aplicativo e inspecione o tráfego. É realmente fácil usar um proxy intermediário para todo o tráfego que entra e sai de um dispositivo móvel. Não seria necessária desmontagem ou engenharia reversa de código para extrair a chave e o segredo do aplicativo nesse caso, devido à natureza da API do Dropbox.
Você pode fazer a pinagem, verificando se o certificado TLS que você recebe do servidor é o esperado. Isso adiciona uma verificação ao cliente e dificulta a interceptação do tráfego. Isso tornaria mais difícil inspecionar o tráfego em voo, mas a verificação de fixação ocorre no cliente, portanto, provavelmente ainda seria possível desativar o teste de fixação. Isso torna ainda mais difícil.
Protegendo o segredo em repouso
Como primeiro passo, usar algo como proguard ajudará a tornar menos óbvio onde os segredos são mantidos. Você também pode usar o NDK para armazenar a chave e o segredo e enviar solicitações diretamente, o que reduziria bastante o número de pessoas com as habilidades apropriadas para extrair as informações. Ocultação adicional pode ser alcançada não armazenando os valores diretamente na memória por um período de tempo; você pode criptografá-los e descriptografá-los imediatamente antes do uso, conforme sugerido por outra resposta.
Opções mais avançadas
Se você está paranóico em colocar o segredo em qualquer lugar do seu aplicativo e tem tempo e dinheiro para investir em soluções mais abrangentes, considere armazenar as credenciais em seus servidores (presumindo que você tenha alguma). Isso aumentaria a latência de qualquer chamada para a API, pois ela teria que se comunicar por meio do servidor e poderia aumentar os custos de execução do serviço devido ao aumento da taxa de transferência de dados.
Você precisa decidir a melhor forma de se comunicar com seus servidores para garantir que eles estejam protegidos. Isso é importante para evitar que todos os mesmos problemas surjam novamente com sua API interna. A melhor regra de ouro que posso dar é não transmitir nenhum segredo diretamente por causa da ameaça do homem do meio. Em vez disso, você pode assinar o tráfego usando seu segredo e verificar a integridade de todas as solicitações que chegam ao seu servidor. Uma maneira padrão de fazer isso é calcular um HMAC da mensagem digitada em segredo. Eu trabalho em uma empresa que possui um produto de segurança que também opera nesse campo e é por isso que esse tipo de coisa me interessa. De fato, aqui está um artigo de blog de um dos meus colegas que analisa a maior parte disso.
Quanto devo fazer?
Com conselhos de segurança como esse, você precisa tomar uma decisão de custo / benefício sobre a dificuldade com que alguém entra. Se você é um banco que protege milhões de clientes, seu orçamento é totalmente diferente de alguém que apóia um aplicativo em sua conta. tempo livre. É praticamente impossível impedir que alguém quebre sua segurança, mas na prática poucas pessoas precisam de todos os sinos e assobios e com algumas precauções básicas, você pode percorrer um longo caminho.
fonte
A solução mais segura é manter as chaves em um servidor e rotear todas as solicitações que precisam dessa chave pelo servidor. Dessa forma, a chave nunca sai do seu servidor, desde que ele esteja seguro, sua chave também. Obviamente, há um custo de desempenho com esta solução.
fonte
Mantenha o segredo
firebase database
e obtenha informações quando o aplicativo for iniciado. É muito melhor do que ligar para um serviço da web.fonte
O que você fizer para proteger suas chaves secretas não será uma solução real. Se o desenvolvedor puder descompilar o aplicativo, não há como proteger a chave, ocultá-la é apenas segurança pela obscuridade, assim como a ofuscação do código. O problema de proteger uma chave secreta é que, para protegê-la, você precisa usar outra chave e ela também precisa ser protegida. Pense em uma chave escondida em uma caixa que está bloqueada com uma chave. Você coloca uma caixa dentro de uma sala e trava a sala. Você fica com outra chave para proteger. E essa chave ainda será codificada dentro do seu aplicativo.
Portanto, a menos que o usuário insira um PIN ou uma frase, não há como ocultar a chave. Mas para fazer isso, você teria que ter um esquema para gerenciar PINs que acontecem fora da banda, o que significa através de um canal diferente. Certamente não é prático para proteger chaves de serviços como APIs do Google.
fonte
Idade pós antigo, mas ainda é bom o suficiente. Eu acho que escondê-lo em uma biblioteca .so seria ótimo, usando NDK e C ++, é claro. Os arquivos .so podem ser visualizados em um editor hexadecimal, mas boa sorte é descompilar: P
fonte
A única maneira verdadeira de manter essas informações privadas é mantê-las no servidor e fazer com que o aplicativo envie o que quer que seja para o servidor, e o servidor interage com o Dropbox. Dessa forma, você NUNCA distribuirá sua chave privada em qualquer formato.
fonte
Com base na experiência amarga, e após consultar um especialista do IDA-Pro, a melhor solução é mover uma parte importante do código para um DLL / SharedObject, buscá-lo em um servidor e carregar em tempo de execução.
Os dados confidenciais devem ser codificados, pois é muito fácil fazer algo assim:
fonte