Introdução
Criar aplicativos móveis seguros requer mais do que apenas um framework poderoso como Flutter. Exige uma abordagem proativa para mitigar ameaças em constante evolução. Neste blog, exploraremos diversas técnicas e práticas recomendadas para proteger aplicações Flutter usando a lista OWASP Mobile Top 10 de 2024 recentemente lançada. Vamos analisar áreas cruciais como o mau uso de credenciais, vulnerabilidades na comunicação, armazenamento de dados problemático e fraquezas na proteção binária, além de medidas para mitigar esses riscos com exemplos.

M1: Uso Improper de Credenciais
Neste risco de segurança, os atacantes podem potencialmente localizar e explorar credenciais codificadas em hardcode ou explorar fraquezas devido ao uso inadequado de credenciais.
Uma vez que essas vulnerabilidades são identificadas, um atacante pode usar credenciais codificadas em hardcode para obter acesso não autorizado a funcionalidades sensíveis do aplicativo. Eles também podem mal utilizar as credenciais, por exemplo, acessando através de credenciais mal validadas ou armazenadas incorretamente, dessa forma contornando a necessidade de acesso legítimo.
Exemplos
- Uso de Credenciais Codificadas em Hardcode no código-fonte.
- Quando o aplicativo comunica-se com um backend, ele compartilha as credenciais do usuário na forma de texto simples ou a visibilidade das chaves da API em formato de texto simples.
- Ainda existem aplicações que armazenam as credenciais do usuário em SharedPreference e isso pode ser visualizado na forma de texto simples.
Um exemplo disso é:
import 'package:shared_preferences/shared_preferences.dart';
final prefs = await SharedPreferences.getInstance();
prefs.setString('username', 'user1234');
String value = prefs.getString('username');
print(value);
Melhores Práticas para Aumentar a Segurança da Gestão de Credenciais
- Avoid using hardcoded credentials in your application’s source code , environment / configuration files.
- Properly handle user credentials by,
- Encrypting credentials during transmission.
- Implement stronger User authentication protocol like Biometrics , Face ID , Touch ID using packages like local_auth , biometricx.
- Avoid storing credentials locally in the device using unencrypted SharedPreferences or Databases storing sensitive information.
- If it is necessary to store any sensitive data, use well known (secure and tested) packages like flutter_secure_storage that uses Keychain based storage for iOS and Keystore for Android.
Aqui está um exemplo de uso do flutter_secure_storage para armazenamento seguro de credenciais:
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
final storage = FlutterSecureStorage();
await storage.write(key: 'API_KEY', value: 'XXXXXXX');
String value = await storage.read(key: 'API_KEY');
print(value);
M2: Insegurança na Cadeia de Fornecimento
Este risco de segurança pode ocorrer quando um atacante pode manipular a funcionalidade do aplicativo explorando vulnerabilidades na cadeia de fornecimento do aplicativo móvel. Isso pode levar à acesso ou manipulação não autorizados dos dados, negação de serviço ou ao controle total sobre o aplicativo móvel ou dispositivo.
Exemplos
- Um atacante pode executar código sem permissão.
- Moderificar o código durante o processo de construção para introduzir códigos maliciosos.
- Explorando vulnerabilidades em bibliotecas de software terceiras, SDKs ou fornecedores.
Melhores Práticas para Fortalecer a Segurança da Cadeia de Fornecimento do Flutter
- Implementar práticas de codificação segura, revisão e teste de código ao longo do ciclo de vida de desenvolvimento do aplicativo móvel para identificar e mitigar vulnerabilidades.
- Asegurar processos de assinatura e distribuição de aplicativos para prevenir que atacantes assinem e distribuam códigos maliciosos. Consulte a Documentação do Flutter sobre como assinar corretamente seu aplicativo para diferentes sistemas operacionais.
- Sempre use a versão mais recente e estável do SDK Flutter, a versão mais atualizada de suas bibliotecas e verifique regularmente as diretrizes de segurança da equipe Flutter e da comunidade em geral de desenvolvimento móvel para reduzir o risco de vulnerabilidades.
M3: Autenticação/Autorização Insegura
Este risco de segurança envolve o uso de métodos fracos de autenticação e autorização que podem ser facilmente explorados por atacantes para obter acesso não autorizado ao aplicativo, seus dados e serviços do back-end.
Exemplos
- Solicitações anônimas sem autenticação.
- Aplicativos que têm uma política de senha fraca como:
- Falta de requisitos mínimos para a extensão e complexidade da senha.
- Autorizando usuários a terem senhas comuns disponíveis publicamente.
- Práticas de gerenciamento de sessões fracos incluem:
- Armazenando IDs de sessão no armazenamento do lado do cliente com permissão para leitura mundial.
- Gerando IDs de sessão sequenciais ou facilmente adivinháveis, tornando-os suscetíveis a ataques de força bruta ou previsão.
- Não anulando sessões ao fazer logout.
- Fornecendo funcionalidades sem verificar papéis.
Melhores Práticas para Melhorar a Segurança de Autenticação
- Evitar autenticação no lado do cliente e reforçar o uso da autenticação no servidor.
- Implemente técnicas fortes de autenticação como OAuth (Open Authorization) usando firebase_auth, que permite aos usuários se autenticarem usando Google, Apple e outros métodos.
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
void main() async {
await initializeFirebaseApp();
await signInWithGoogle();
}
Future<void> initializeFirebaseApp() async {
await Firebase.initializeApp();
}
Future<void> signInWithGoogle() async {
try {
final GoogleSignInAccount googleUser = await GoogleSignIn().signIn();
final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
UserCredential userCredential = await FirebaseAuth.instance.signInWithCredential(credential);
....
} catch (e) {
....
}
}
- Implementar Políticas de Senha Fortes (
firebase_authfornece essa funcionalidade) - Para problemas como Força Bruta em Credenciais, implemente um limite de tentativas de login falhas
Melhores Práticas para Melhorar a Segurança da Autorização
- Verifique independentemente os papéis e permissões do usuário autenticado no sistema de backend.
- Lide com solicitações não autorizadas de forma segura.
M4: Falta de Validação de Entrada/Saída
Toda aplicação móvel funciona com base na entrada do usuário. Se a entrada do usuário não for validada e sanitizada, isso pode levar a vulnerabilidades sérias como Injeção SQL / Comando, XSS e se esses ataques forem combinados com outras vulnerabilidades, podem levar ao acesso não autorizado de dados, corrupção da memória e potencialmente comprometer todo o sistema móvel.
Exemplos
- Ataques de Injeção:
- Injeção SQL: Consultas SQL maliciosas podem ser injetadas por meio da entrada do usuário, potencialmente levando a acesso não autorizado, modificação ou exclusão de dados.
- Injeção de Comandos: Comandos injetados podem executar código arbitrário no servidor, comprometendo sua segurança e estabilidade.
- Cross-Site Scripting (XSS): Scripts maliciosos podem ser injetados na saída, potencialmente roubando credenciais de usuários ou redirecionando-os para sites prejudiciais.
- Execução Remota de Código (RCE): Entrada do usuário não validada, especialmente em solicitações da rede ou operações de arquivo local, pode ser usada para executar código arbitrário no dispositivo.
- Gestão Inadequada de Erros: Tratamento insuficiente de erros pode inadvertidamente revelar informações sensíveis ou expor vulnerabilidades em mensagens de erro.
- Corrupção da Memória: Entradas maliciosas podem levar a sobreposições de buffer ou outros problemas de corrupção da memória, potencialmente fazendo com que o aplicativo pare ou permitindo que os atacantes obtenham controle.
Melhores Práticas para Validação Robusta de Entrada e Saída
- Validação da Entrada:
- Valide e limpe a entrada do usuário usando técnicas de validação rigorosas. Use bibliotecas disponíveis como
validatorspara automatizar tarefas de validação.
- Valide e limpe a entrada do usuário usando técnicas de validação rigorosas. Use bibliotecas disponíveis como
Aqui está um exemplo de uso:
import 'package:validators/sanitizers.dart';
import 'package:validators/validators.dart';
print(isEmail('sampletext')); // Imprime False
print(isJSON('{Exemplos
- Falta de verificação de certificado, como usar
HttpURLConnection diretamente sem validação adequada do certificado em Android e definir allowsAnyHTTPSCertificate para true em NSURLSession no iOS, o que significa que o aplicativo aceita qualquer certificado de servidor, independentemente da sua legitimidade.
- Não usar canais SSL/TLS durante a transmissão.
- O uso de cifras fracas ou depreciadas em conexões SSL/TLS torna-as vulneráveis a ataques de descriptografia.
Melhores Práticas para Segurança da Comunicação em Aplicativos Flutter
- Aplique SSL/TLS aos canais de transporte que o aplicativo móvel usará para transmitir dados para um backend API ou serviço web.
- Use certificados assinados por uma CA confiável.
- Só estabeleça uma conexão segura após verificar a identidade do servidor final usando certificados confiáveis na chave de cadeia.
- Considere o pinning de certificado. (http_certificate_pinning para pinning de certificado em Flutter)
Aqui está um exemplo do seu uso:
import 'package:http_certificate_pinning/secure_http_client.dart';
SecureHttpClient getClient(List<String> allowedSHAFingerprints){
final secureClient = SecureHttpClient.build(certificateSHA256Fingerprints);
return secureClient;
}
myRepositoryMethod(){
secureClient.get("sampleurl.com");
}
}
M6: Controles de Privacidade Insuficientes
Este risco é sobre a proteção de Informações Pessoais Identificáveis (PII) como nomes e endereços, informações de cartão de crédito, e-mail, informações sobre saúde, religião, sexualidade e opiniões políticas.
Ameaças podem divulgar, manipular ou destruir essas informações, causando danos às pessoas envolvidas.
Este risco de segurança pode ocorrer através
- Armazenamento e comunicação de dados inseguros (M5, M9).
- Acesso não autorizado a dados devido à autenticação e autorização inseguras (M3, M1).
- Ataques ao sandbox do aplicativo (M2, M4, M8).
Exemplos
- A coleta de mais PII do que absolutamente necessário para a funcionalidade essencial do aplicativo.
- O armazenamento de PII em texto simples, locais inseguros ou sem criptografia adequada, deixando-o vulnerável ao acesso não autorizado.
- Uma política de privacidade vaga ou enganosa falha em informar os usuários sobre as práticas de coleta, uso e compartilhamento de dados, dificultando o consentimento informado.
Melhores Práticas para Implementação de Controles de Privacidade Efetivos
- Minimize a quantidade de informações pessoais que o aplicativo coleta.
- Implemente controles de acesso granulares com base em papéis do usuário, permissões e o princípio da mínima privilégio.
- A informação coletada deve ser armazenada ou transferida apenas se absolutamente necessário. Se for necessário, a informação deve ser armazenada ou transmitida seguramente com autenticação e autorização adequadas (como discutido nos riscos anteriores).
M7: Proteção Binária Insuficiente
Este risco pode ser dividido em duas partes:
- Engenharia Reversa: Um atacante geralmente baixará o aplicativo alvo de uma loja de aplicativos e analisará em seu próprio ambiente local usando um conjunto de diferentes ferramentas. Isso pode coletar chaves API comerciais ou segredos criptográficos codificados diretamente que podem ser usados indevidamente, ou pode desmontar o aplicativo para descobrir vulnerabilidades e explorá-las.
- Manipulação de Código: Os atacantes também poderiam manipular binários do aplicativo para acessar recursos pagos gratuitamente ou para contornar outros verificadores de segurança. Isso permitiria que os atacantes modificassem o aplicativo e distribuíssem a versão modificada com código malicioso de volta aos usuários.
Exemplos
- Aplicativos que não obfuscam seu código são vulneráveis à análise do código-fonte. Isso é mais prevalente em aplicativos Flutter que lançam sua APK no modo Debug, onde o código Dart pode ser facilmente extraído de kernel
blob.bin.
- Superar verificadores de segurança para Mods e obter acesso não autorizado a recursos premium.
- Reembalar o aplicativo com características maliciosas.
Melhores Práticas para Aplicar Técnicas de Proteção Binária
- O aplicativo deve verificar em tempo real se sua integridade foi comprometida ou não.
- Lance versões Release do aplicativo Flutter. (A versão Release do Flutter é fortemente desmantelada e obfuscada, tornando difícil a engenharia reversa.)
M8: Configuração Inadequada de Segurança
A configuração inadequada da segurança em aplicativos móveis refere-se à configuração incorreta das configurações, permissões e controles de segurança que podem levar a vulnerabilidades e acesso não autorizado.
Exemplos
- Requisitar permissões desnecessárias como:
- No Android, conceder
READ_EXTERNAL_STORAGE ou WRITE_EXTERNAL_STORAGE quando o armazenamento interno ou mecanismos de armazenamento limitado são apropriados.
- Sobrecarregar capacidades amplas como câmera ou fotos quando permissões granulares, como
cameraCaptureMedia ou photoLibraryAdd, estão disponíveis.
- Transmitir dados sensíveis por HTTP em vez de HTTPS.
- Mecanismos de armazenamento não protegidos, como o uso de Shared Preferences ou a utilização de localizações de armazenamento com permissões de leitura do mundo.
Melhores Práticas para Evitar Configurações Inadequadas de Segurança
- Configurar a configuração da rede seguramente por:
- No
AndroidManifest.xml, configure cleartextTrafficPermitted como false para não permitir o tráfego HTTP.
- Use os pacotes
http ou dio para solicitações de rede.
- Evite solicitar permissões excessivamente permisivas. Use o pacote
permission_handler para solicitar e gerenciar permissões. (Funciona tanto no ambiente Android quanto iOS.)
import 'package:permission_handler/permission_handler.dart';
Future<void> _requestCameraPermission() async {
final status = await Permission.camera.request();
if (status == PermissionStatus.granted) {
print('Camera permission granted');
} else {
print('Camera permission denied');
}
}
- Avoid keeping debug features (like logging statements) in production mode.
M9: Insecure Data Storage
Com a rápida proliferação de aplicativos móveis em diversas plataformas, o tratamento e armazenamento de dados sensíveis do usuário tornaram-se focos importantes para vulnerabilidades de segurança. Se informações sensíveis armazenadas nos dispositivos móveis não forem protegidas adequadamente, isso abre a porta para uma série de problemas. Da acessibilidade não autorizada ao risco à privacidade e até mesmo colocando organizações em perigo, as consequências são graves.
Exemplos
- Armazenar senhas, tokens de acesso ou outras credenciais sensíveis diretamente no código, preferências compartilhadas ou arquivos locais sem criptografia.
- Cachear dados sensíveis (por exemplo, perfis do usuário, respostas da API) sem controles de acesso adequados ou criptografia, tanto em memória quanto no disco.
- Registrar informações sensíveis (por exemplo, logs de depuração, solicitações de rede) em arquivos de texto simples ou logs de console acessíveis aos usuários ou atacantes.
- Manipulação inadequada das permissões de arquivo e APIs.
Melhores Práticas para Proteger o Armazenamento de Dados em Flutter
- Utilize a Android Keystore ou KeyChain para armazenar chaves e dados sensíveis com suporte à hardware.
- Implemente controles de acesso granulares baseados nos papéis e permissões do usuário.
- Limite a quantidade de informações sensíveis registradas.
- Empregue métodos de criptografia em arquivos armazenados localmente para maior segurança. (Use pacotes como hive, flutter_secure_storage para armazenar dados em arquivos criptografados.)
Aqui está um exemplo de uso do hive para proteger o armazenamento de dados:
import 'package:hive/hive.dart';
var box = Hive.box('data');
box.put('user', 'user1');
var name = box.get('user');
print(name);
M10: Insuficiente Criptografia
Ao falar sobre este risco de segurança que foi colocado em M5 na Lista OWASP Top 10 de 2016, discute-se como os atacantes exploram métodos criptográficos inseguros empregados em diferentes aplicativos móveis que podem comprometer a confidencialidade, integridade e autenticidade de informações sensíveis. Sua intenção é descriptografar informações sensíveis ou determinar as chaves criptográficas usadas.
Exemplos
- Um atacante intercepta a comunicação entre o aplicativo e um servidor, capturando e potencialmente modificando dados em texto simples.
- Débil criptografia de chaves ou requisitos fracos de senhas permitem que os atacantes descubram esses dados usando ferramentas automatizadas.
- Vulnerabilidades em bibliotecas criptográficas ou implementações personalizadas podem criar fraquezas exploráveis.
- Práticas fracas de gerenciamento de chaves, como armazenar chaves em texto simples, codificá-las no aplicativo ou usar geração de chaves previsíveis, comprometem a segurança dos dados.
Melhores Práticas para Utilizar Métodos Criptográficos Fortes
- Deixe de usar algoritmos criptográficos obsoletos. (Use pacotes populares de criptografia como encrypt, crypto, pointycastle)
Aqui está um exemplo de uso:
import 'package:encrypt/encrypt.dart';
void main() {
final plainT = 'Este é um texto de exemplo';
final key = Key.fromUtf8('uma_chave_secreta');
final iv = IV.fromLength(16);
final encryptObj = Encrypter(AES(key));
final encrypted = encryptObj.encrypt(plainText, iv: iv);
final decrypted = encryptObj.decrypt(encrypted, iv: iv);
print(decrypted);
}
-
Armazene chaves criptográficas de maneira segura.
- Utilize o Android Keystore ou KeyChain para armazenamento de chave baseado em hardware.
- Use funções derivadas de chave (KDFs) como PBKDF2 para geração de chaves com base em senha.
- Roteie chaves regularmente para reduzir a superfície de ataque.
-
Realize testes de segurança regulares. Integre ferramentas de análise estática de código como Dart analyzer ou linters (por exemplo, flutter_analyze) para identificar vulnerabilidades criptográficas potenciais cedo no desenvolvimento. Consulte esta documentação para saber mais sobre flutter_analyze.
-
Use funções de hash fortes com KDFs como PBKDF2 ou Argon2 para aumentar o custo computacional e resistir a ataques de tabela-rainha. (Para implementação de Argon2, use a biblioteca dargon2_flutter.)
Conclusão
Aqui está um resumo do nosso post sobre tornar aplicativos Flutter mais seguros, com base no OWASP Mobile Top 10 para 1024: manter nossos aplicativos seguros é extremamente importante, e o Flutter nos fornece várias bibliotecas e APIs para ajudar. É tudo sobre garantir que estamos fazendo as coisas básicas corretamente, como monitorar quem está acessando o quê, tornar nosso código difícil de adulterar e manter privado o que deve ser privado. Ao aplicar as medidas de segurança discutidas aqui, você não apenas protege seus aplicativos, mas também constrói confiança com seus usuários.

