A segurança da informação está em voga. O advento da Indústria 4.0 põe as tecnologias de informação e comunicação em uma posição de importância e destaque que requer proteção na mesma medida. Ataques cibernéticos são cada vez mais comuns e automatizados, o que demanda cautela dos projetistas e desenvolvedores de hardware e software.
No escopo da mobilidade, os agentes responsáveis pela segurança são os fabricantes de celulares e os desenvolvedores de aplicações. A parte que cabe aos fabricantes vem sendo cumprida nos últimos anos, o que pode ser visto pela evolução, tanto dos componentes físicos usados nos aparelhos, quanto dos sistemas operacionais, que definem as APIs com que os aplicativos interagem. Este texto dá enfoque à outra ponta do ecossistema: os desenvolvedores de apps, especificamente do sistema Android.
Segurança em mente
Aplicar conceitos de segurança da informação no desenvolvimento de software é uma tarefa complexa. Uma das razões é que o objetivo não é atingido simplesmente ao se seguir uma metodologia ou rodar um programa de auditoria. O alvo dos ataques não é apenas o software criado, mas sim várias outras frentes, como as credenciais dos desenvolvedores, a infraestrutura em que o código é armazenado ou executado, ou os usuários do programa final. Nesse ponto, a segurança da informação se alinha à segurança das operações (OPSEC) nos objetivos a serem alcançados.
Uma análise qualitativa da segurança empenhada no código-fonte deve levar em conta o modelo de ameaça (threat model, em inglês) a que a aplicação estará sujeita. Para ilustrar, suponha que uma app armazene dados sensíveis do usuário. Que atores maliciosos poderão tentar obter essas informações lançando mão de qualquer meio? Por exemplo: outro app instalado no celular, outra pessoa em posse do aparelho, um malware infiltrado, um Estado nacional. Quais ameaças são factíveis e quais são os recursos necessários para impedi-las? As respostas para essas perguntas trarão as diretivas para o desenvolvimento seguro.
Um caso: como armazenar uma senha?
Uma senha de usuário é, por motivo óbvio, um dado sensível que oferece risco de ser usada maliciosamente caso não seja devidamente protegida. Antes de armazenar, a primeira questão a ser levantada é se a senha pode ser substituída por um identificador de sessão ou algo similar. Caso a arquitetura da aplicação em desenvolvimento permita a troca, o OAuth ou as APIs de credenciais do Android e do Google são meios mais seguros de autenticação que não envolvem lidar diretamente com senhas.
Caso seja necessário guardar a senha em armazenamento persistente, a documentação do Android sugere salvar um arquivo em armazenamento interno. É uma abordagem razoável, que impede o acesso simples por outras apps, mas uma aplicação com permissão root, se este for um risco a se considerar, é capaz de obter a informação facilmente.
Um meio de proteger ainda mais a senha ou qualquer informação sensível é criptografar os dados de interesse com uma chave protegida pelo sistema. Esse recurso do Android traz várias vantagens:
- O uso da chave e a operação criptográfica é feita em um processo de sistema, portanto o conteúdo da chave não é repassado à aplicação do usuário;
- A chave pode ser armazenada em hardware seguro dentro do celular, então mesmo que um atacante comprometa o sistema operacional e possa usar a chave, esta não pode ser extraída;
- O uso da chave pode estar condicionado à autorização e à autenticação explícita do usuário, portanto, os dados criptografados podem estar protegidos mesmo com o aparelho em posse de outra pessoa.
Por meio dessa API é possível gerar e utilizar uma chave AES e criptografar uma senha ou, de modo mais abrangente, qualquer tipo de dado que se queira proteger com a cifra AES-GCM.
Segue código simplificado de exemplo para entendimento:
// Carrega keystore do Android, específico para cada aplicação.
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
// Cria chave AES para encriptação e decriptação de cifra AES-GCM.
// A chave criada requer que o dispositivo esteja desbloqueado para efetuar a decriptação.
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder("my_key",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT);
builder.setBlockModes(KeyProperties.BLOCK_MODE_GCM);
builder.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE);
builder.setUnlockedDeviceRequired(true);
keyGenerator.init(builder.build());
Key key = keyGenerator.generateKey();
// Insere chave no keystore.
keyStore.setKeyEntry("my_key", key, null, null);
// Encripta uma senha com uso da cifra AES-GCM.
// Note que a cifra é capaz de encriptar qualquer sequência de bytes.
byte[] password;
int passwordLength;
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, keyStore.getKey("my_key", null));
// As três variáveis abaixo são necessárias para posterior decriptação.
byte[] encrypted;
int encryptedLength = cipher.doFinal(password, 0, passwordLength, encrypted, 0);
byte[] nonce = cipher.getIV();
// Decripta a senha cifrada por AES-GCM.
cipher = Cipher.getInstance("AES/GCM/NoPadding");
AlgorithmParameterSpec gcmSpec = new GCMParameterSpec(128, nonce);
cipher.init(Cipher.DECRYPT_MODE, keyStore.getKey("my_key", null), gcmSpec);
// Recupera a senha.
byte[] decrypted;
int decryptedLength = cipher.doFinal(encrypted, 0, encryptedLength, decrypted, 0);
Um projeto de aplicativo Android que exercita as APIs de chaves e cifras pode ser acessado no link: https://github.com/nandsito/android-example-aes-gcm
Uma ressalva: o uso de cifras criptográficas requer cuidado nos detalhes, pois um parâmetro equivocado ou um detalhe importante dos algoritmos que, porventura, é relevado, pode causar vazamento de informações sensíveis. Por exemplo, o reúso do vetor de inicialização, ou nonce, na cifra AES-GCM pode comprometer a confidencialidade da chave. Então é interessante que se conheça bem os algoritmos criptográficos usados.
Conclusão
A segurança da informação é um tema multidisciplinar e traz consigo a complexidade inerente de sua natureza. Isso foi ilustrado com a apresentação de tópicos relacionados – OPSEC, modelo de ameaça, criptografia – e a aplicação de todos esses conceitos no caso concreto do armazenamento de senhas. O fato de não haver uma solução única ou simples para a dada situação demonstra que a área de segurança tem potencial de pesquisa e inovação, principalmente para os problemas vindouros de tecnologias futuras.