Evite subir chaves de API para o GitHub em seu projeto Android, veja como.
Tags: android, tutorial, security, github
Published: 2020-12-04 16:10:58

######Imagem de capa por [Bruno Martins @ Unsplash](https://unsplash.com/@brunus)

#**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](https://olhardigital.com.br/2020/05/18/noticias/computador-quantico-deve-quebrar-criptografia-do-bitcoin-em-dois-anos);
- 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](https://saude.estadao.com.br/noticias/geral,vazamento-de-senha-do-ministerio-da-saude-expoe-dados-de-16-milhoes-de-pacientes-de-covid,70003528583).

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>](https://pt.wikipedia.org/wiki/Modelo_cliente–servidor);

- **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>](https://www.origiweb.com.br/dicionario-de-tecnologia/API);

- **Segredo, token ou chave de API** é um identificador único utilizado na autenticação de um cliente num serviço[<3>](https://cloud.ibm.com/docs/account?topic=account-manapikey&locale=pt-BR);

- **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>](https://pt.wikipedia.org/wiki/Programação_automática).

###**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](https://cloud.google.com/maps-platform/pricing?hl=pt);
- 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] (https://developer.android.com/studio/build/gradle-tips) 
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: 

```groovy
api.key=API_KEY_HERE
```

####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:

```groovy
/keys.properties
```

- 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:

```groovy
// 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'),]
```

####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:

```groovy
buildscript {
    apply from: project.rootProject.file("keys.gradle")

    ...

}
```

- 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:

```groovy
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
        }
}
```

####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:

```kotlin
class CustomApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        Firebase.init(this, BuildConfig.API_KEY)
    }
}
```

####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](https://developer.android.com/studio/build/shrink-code) 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!_