DEV Community

Cover image for Evite subir chaves de API para o GitHub em seu projeto Android, veja como.
Leehendry Pauletto
Leehendry Pauletto

Posted on • Edited on

Evite subir chaves de API para o GitHub em seu projeto Android, veja como.

Imagem de capa por Bruno Martins @ Unsplash

Aviso

  • Nenhuma medida por si só tornará nossas aplicações seguras. A segurança dum app depende duma combinação de medidas, e até mesmo as sofisticadas podem ser quebradas;
  • Dito isso, destaco que este tutorial não consiste numa bala de prata para todos os nossos problemas de segurança, mas numa medida que pode deixar nossos apps menos sujeitos a vazamentos de dados.

Não li, nem lerei

  • Chaves de API são utilizadas para autenticação de clientes em serviços específicos;
  • A revelação de informações sensíveis, como as chaves de API, pode acarretar usos e consequências não planejados;
  • BuildConfig do Gradle permite ao nosso projeto ler dados sensíveis contidos num arquivo local, na forma de código gerado.

Contexto

A divulgação de dados sensíveis tem o potencial de causar danos tanto aos nossos próprios interesses quanto aos das pessoas impactadas por nossos projetos.

Embora tenha focado em chaves de API, outros dados sensíveis como endpoints e credenciais também podem ser guardados localmente com a abordagem descrita aqui.

Os quês

Antes de tudo, é melhor termos a certeza de que estamos falando das mesmas coisas:

  • Cliente refere-se ao software ou hardware que faz uso dos serviços disponíveis num servidor, no modelo cliente-servidor <1>;

  • API significa Interface de Programação de Aplicativos, que, em termos gerais, é um conjunto de regras a serem observadas na comunicação entre programas, geralmente um cliente e um serviço <2>;

  • Segredo, token ou chave de API é um identificador único utilizado na autenticação de um cliente num serviço<3>;

  • Geração de código é o processo pelo qual um compilador converte representações de código em instruções que podem ser prontamente executadas pelo dispositivo <4>.

Os porquês

  • Chaves de API permitem identificar clientes e são geradas para fins específicos. Por isso, é comum que a conta do cliente incorra em custos de acordo com as quotas de uso do serviço. - Google Maps Platform é um bom exemplo disso, já que os preços variam conforme a utilização;
  • Evitar a revelação dessas chaves é fundamental na prevenção de usos indevidos.

Apesar disso, o versionamento de chaves de API é um erro que não apenas eu mesmo cometi no passado, mas que também vi colegas de profissão cometerem, independentemente da experiência.

A verdade é que, infelizmente, práticas de Segurança da Informação ainda são pouquíssimo divulgadas nas nossas comunidades de desenvolvimento.

O como

  • A classe BuildConfig do Gradle permite a leitura de valores a partir de arquivos locais e a disponibilização deles na forma de código gerado;
  • Contanto que indiquemos corretamente os arquivos no .gitignore, a divulgação das nossas chaves de API no GitHub, GitLab e afins não deverá ser um problema.

O código

São oito as etapas:

1. Criar keys.properties na raiz

  • Na raiz do projeto, crie um arquivo chamado keys.properties e adicione a ele a chave da API desta forma:
api.key=API_KEY_HERE
Enter fullscreen mode Exit fullscreen mode

2. Adicionar o caminho do arquivo .gitignore

  • Muita atenção a esta etapa, pois o .gitignore é que indica quais arquivos ficam fora do versionamento!
  • Para prevenir o versionamento do keys.properties, adicione o caminho do arquivo ao .gitignore desta forma:
/keys.properties
Enter fullscreen mode Exit fullscreen mode
  • Rode no terminal o comando git status. O arquivo keys.properties não deverá estar listado para versionamento. Caso esteja, significa que a configuração do .gitignore está errada! Repita a etapa.

3. Criar keys.gradle na raiz

  • Para recuperar os valores do keys.properties, adicione à raiz do projeto um arquivo chamado keys.gradle, onde o seguinte código Groovy será adicionado:
// Define como carregar as informações do arquivo local
def getStringFromFile(fileName, property) {
    Properties props = new Properties()

    props.load(project.rootProject.file(fileName).newDataInputStream())

    return props[property].toString()
}


// Indica keys.properties como o arquivo para recuperação dos valores
def getStringFromKeysFile(property) {
    return getStringFromFile('keys.properties', property).toString()
}


// Expõe a chave definida no keys.properties como uma variável para uso em todo o projeto
ext.keys = ["apiKey": getStringFromKeysFile('api.key'),]
Enter fullscreen mode Exit fullscreen mode

4. Importe keys.gradle dentro do project/build.gradle

  • Para utilizar os métodos definidos no keys.gradle, importe o arquivo dentro do build.gradle do projeto:
buildscript {
    apply from: project.rootProject.file("keys.gradle")

    ...

}
Enter fullscreen mode Exit fullscreen mode
  • A esta altura, a BuildConfig já consegue automaticamente converter nossa chave em código compilado -- mas só faremos isso na etapa 6.

5. Definir uma constante para a chave dentro do app/build.gradle

  • Defina uma constante chamada API_KEY no build.gradle do app desta forma:
android {

...

    buildTypes {

     // Embora esteja configurado para 'debug', certifique-se de quais build variants (debug, staging, release etc) precisarão da chave:
        debug {

            ...

            it.buildConfigField "String", "API_KEY", keys.apiKey
        }
}
Enter fullscreen mode Exit fullscreen mode

6. Limpar e recompilar o projeto

  • Para que o código seja efetivamente gerado, selecione Build > Clean Project e depois Build > Rebuild Project no menu superior do Android Studio.

7. Chamar a variável via BuildConfig dentro do projeto

  • Chame a constante via BuildConfig.API_KEY, conforme etapa 5, onde for necessário no código. Por exemplo:
class CustomApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        Firebase.init(this, BuildConfig.API_KEY)
    }
}
Enter fullscreen mode Exit fullscreen mode

8. Compartilhar o arquivo keys.properties de forma segura dentro do time

  • Já que evitamos o versionamento da chave da API, é necessário utilizar uma maneira segura de compartilhar o keys.properties entre as pessoas da equipe;
  • Caso seu trabalho conte com um time de Segurança da Informação, verifique com ele qual a melhor forma de compartilhar o arquivo;
  • Do contrário, ferramentas como 1Password podem ajudar, já que permitem a gestão de direitos de acesso aos arquivos.

Considerações finais

  • Outras informações sensíveis como endpoint e credenciais também pode sem mantidas localmente com essa abordagem;
  • Nomes como keys.properties, api.key, keys.gradle e API_KEY são arbitrários -- apenas mantenha as extensões (.properties, .key, .gradle) ao renomear;
  • NOTE QUE BuildConfig gera código compilado, o que significa que engenharia reversa do .apk ainda pode expor chaves de API e outros segredos;
  • Apenas a combinação de medidas de segurança pode nos ajudar a manter nossos apps seguros. Busque também ferramentas de otimização e ofuscação de código como R8 para reduzir as chances de vazamento de dados.

Agradecimentos especiais ao Victor Vieira por me ensinar essa abordagem há um ano; e ao Walmyr Carvalho por me estimular a escrever aqui no dev.to!

Top comments (0)