Como começar a proteger a segurança do React Native
Kingsley Ubah
7 de abril de 2022
0 minutos de leituraO React oferece uma maneira simples e intuitiva de criar interfaces de usuário interativas. Com ele, você pode criar aplicações complexas a partir de pequenas partes de código isoladas, chamadas componentes. O React Native é uma extensão do React que permite combinar técnicas usadas em tecnologias web, como JavaScript, com o React para criar apps móveis multiplataforma.
Isso permite que desenvolvedores escrevam o código uma única vez para várias plataformas, acelerando o desenvolvimento. O React Native usa um DOM virtual para executar componentes e código de aplicações em dispositivos com Android, Android TV, iOS, macOS, tvOS, web, Windows e UWP.
Essa adoção é ótima para o React, já que a tecnologia móvel está crescendo e evoluindo em um ritmo sem precedentes. Até 2025, haverá uma estimativa de 7,49 bilhões de usuários de dispositivos móveis no mundo todo. Os apps móveis são onipresentes e estão se tornando mais sofisticados no compartilhamento, tratamento e proteção dos dados dos usuários.
Como desenvolvedor de uma aplicação voltada para usuários, é sua responsabilidade proteger as informações dos usuários do app e manter seguras outras informações confidenciais do servidor. Por isso, você precisa tomar medidas para garantir que cada pessoa veja apenas o que tem autorização para acessar e que as informações dos usuários armazenadas no banco de dados permaneçam seguras.
Para ajudar a proteger as informações dos usuários finais, é essencial que os apps não exponham chaves privadas, informações de bancos de dados, arquivos confidenciais nem partes da página que revelem a estrutura ou as operações do back-end. Vamos conhecer alguns desafios de segurança enfrentados por desenvolvedores de React Native ao criar apps móveis, como a transferência segura de dados, os protocolos de autenticação e as vulnerabilidades em dependências. Também veremos como resolver cada um desses desafios.
Transferência segura de dados
É difícil pensar em um app móvel que não precise de dados de um servidor remoto. Por padrão, o React Native usa apenas HTTPS para chamadas de API e transferências de dados.
Embora seja possível substituir essa configuração padrão, o uso de um protocolo que não seja HTTPS pode causar problemas com o fornecedor ao publicar o app na loja de aplicativos. Mais grave ainda, isso pode expor seu app móvel a vários tipos de violação de dados.
Você pode fixar manualmente o(s) certificado(s) confiável(is) do host remoto no app móvel para evitar ataques de intermediário (MITM) e aumentar a segurança do app. Há várias bibliotecas de código aberto adequadas para fixação de certificados no React Native, como react-native-ssl-pinning, de MaxToyberman, e react-native-cert-pinner, da Approov.
Fixação com a biblioteca React Native SSL pinning
O React Native SSL pinning converte certificados em arquivos .cer, que você pode adicionar como recursos ao pacote do app móvel, assim como faria com uma imagem ou uma fonte personalizada.
A ferramenta oferece uma alternativa a fetch, que podemos usar para fazer nossas solicitações HTTP.
Para fixar um certificado, use este código:
Para fixar uma chave pública, use este código:
Por trás da interface, a biblioteca usa dois módulos nativos: AFNetworking para iOS e okhttp3 para Android. O módulo AFNetworking usa automaticamente arquivos .cer nos recursos. O OkHttp3 usa a propriedade JavaScript sslPinning para fazer o mapeamento para .cer.
Fixação com react-native-cert-pinner
react-native-cert-pinner é outra biblioteca que permite fixar certificados no app móvel. As fixações podem ser o hash SHA256 em Base64 da chave pública do certificado ou o hash SHA1 em Base64 do certificado.
A biblioteca oferece o utilitário pinset, que gera um arquivo info.plist no iOS ou um arquivo GeneratedCertificatePinner.java no Android. Em seguida, o código nativo faz a vinculação a esse arquivo.
Por trás da interface, a biblioteca usa o TrustKit no iOS e o okhttp3 no Android.
Para fazer a fixação usando react-native-cert-pinner, primeiro gere uma configuração inicial com este comando:
Após a inicialização, determine quais URLs serão fixadas e o hash da chave pública de cada certificado.
Em seguida, insira no arquivo pinset.json os hashes das chaves públicas desejadas para seu domínio:
Observação: Domínios iniciados por um asterisco (*) incluem todos os subdomínios.
Agora, gere os arquivos-fonte do projeto nativo com o seguinte comando:
Essa ação deve gerar os respectivos arquivos:
Recomendamos usar uma biblioteca que permita fixar a chave pública do certificado, pois uma fixação criada a partir do certificado deixa de funcionar quando ele expira. As duas bibliotecas abordadas nesta seção permitem fixar chaves públicas.
Em geral, é uma boa prática fixar certificados em um app móvel apenas quando você quiser ter bastante certeza da identidade de um host remoto.
Protocolos de autenticação
A autenticação ajuda a estabelecer confiança ao identificar o usuário ou sistema específico por trás de uma solicitação de rede. Essa identificação ajuda o servidor a decidir se deve permitir que o usuário acesse determinado recurso.
A maioria dos apps móveis precisa exibir algum tipo de dado personalizado para o usuário. Pense no perfil de uma pessoa no app do Facebook ou na lista de contatos do WhatsApp. O sistema de autenticação ajuda o servidor a identificar o usuário e entregar os dados correspondentes nesses apps.
Uma maneira comum de configurar a autenticação de usuários no React Native é criar grupos de telas diferentes. Desenvolvedores costumam fazer isso com uma biblioteca de roteamento, como o Stack Navigator.
Um grupo gerencia as telas que usuários não autenticados podem encontrar, como as telas de login, cadastro e redefinição de senha. O app usa essas telas para autenticar o usuário.
Um segundo grupo é destinado a usuários autenticados. Essa pilha inclui telas de painel, configurações, conta, feed e outras relacionadas ao conteúdo do usuário.
Este exemplo de código divide as telas em dois grupos: AppStack para usuários autenticados e AuthStack para usuários não autenticados:
Depois de criar os dois grupos de telas, crie um componente Router responsável por escolher qual pilha exibir com base no status de autenticação do usuário.
Em seguida, use as duas pilhas dentro de NavigationContainer. Um componente de react-navigation envolve toda a navegação por rotas no React Native.
authData representa os dados que o usuário fornece na tela de autenticação — por exemplo, SignInScreen. Este código autentica o usuário:
A função signIn se conecta à API e atualiza authData com base na resposta. Você pode armazenar ali os dados do perfil do usuário recebidos da API. A função signOut apaga os dados. Em alguns casos, ela pode se conectar à API para invalidar um token.
Um estado de carregamento é necessário porque o processo de autenticação é assíncrono e leva tempo para ser concluído. Você pode acompanhar esse estado para exibir uma animação de carregamento na interface do usuário (UI) do app enquanto o servidor processa a solicitação.
Por fim, garanta que todos os componentes possam acessar o Context envolvendo-o com AuthContext.Provider.
O protocolo OAuth 2.0
Aplicações móveis React Native costumam usar o protocolo de autenticação OAuth 2.0 para autenticar usuários. O OAuth é uma opção popular para apps web e móveis por oferecer segurança rigorosa.
Os quatro participantes de um fluxo OAuth são:
Proprietário do recurso: É quem possui os dados no servidor de recursos. Por exemplo, um usuário do Facebook é o proprietário dos dados do próprio perfil no Facebook.
App cliente: A aplicação que quer acessar esses dados (por exemplo, o app móvel do Facebook).
Servidor de recursos: A API que armazena os dados que a aplicação móvel quer acessar (por exemplo, a API do Facebook).
Servidor de autorização: O principal mecanismo do OAuth.
O OAuth solicita que os usuários se autentiquem por meio de um serviço de terceiros, como Google, Facebook ou GitHub. Quando o processo de autenticação é concluído, o serviço de terceiros redireciona o usuário para a aplicação com um código de verificação. A aplicação pode trocar esse código por um JSON Web Token (JWT) ou outro tipo de token.
Esses redirecionamentos são seguros para apps web porque as URLs são garantidamente exclusivas na web. Porém, apps móveis não têm um método centralizado para registrar esquemas de URL.
Para resolver esse problema de segurança, precisamos adicionar uma verificação chamada PKCE (pronuncia-se “Pixie”), uma extensão da especificação OAuth 2.0. A PKCE usa o algoritmo de hash criptográfico SHA 256 para verificar se as solicitações de autenticação e troca de tokens vêm do mesmo cliente.
Essa abordagem garante que somente a aplicação responsável pelo fluxo de autorização possa trocar o código de verificação por um JWT.
Uma maneira simples de implementar OAuth nativo com segurança no React Native é usar um pacote como react-native-app-auth. Ele funciona como uma ponte do React Native para os SDKs AppAuth do iOS e do Android, que se comunicam com provedores OAuth 2.0 e OpenID Connect.
O pacote oferece suporte à PKCE e a vários provedores OpenID e OAuth 2.0, incluindo Google, Okta, GitHub, Coinbase e FusionAuth.
Faça uma varredura em busca de vulnerabilidades em dependências
Desenvolvedores não criam sozinhos uma aplicação nativa completa com React Native. Muitas vezes, usamos ferramentas de terceiros para resolver problemas e aumentar a produtividade.
Uma aplicação contém várias dependências de terceiros que ajudam a torná-la completa e funcional. O problema é que essas dependências podem introduzir vulnerabilidades na aplicação, mesmo quando nosso próprio código é seguro.
Há algumas maneiras de começar a usar o Snyk para detectar vulnerabilidades em pacotes de código aberto. Vamos ver um exemplo com o popular app de arte de código aberto para React Native Eigen.
A primeira opção é usar a Snyk CLI: instale a ferramenta CLI e crie uma conta gratuita no Snyk. Depois de criar a conta e instalar a ferramenta, execute snyk auth para conectar a CLI à sua conta.
Clone o repositório no seu ambiente de desenvolvimento e execute snyk test no diretório raiz do projeto clonado. Isso fará uma varredura do manifesto de pacotes na raiz em busca de problemas com as versões dos pacotes.
Dica útil: Você também pode executar snyk monitor para receber alertas sobre problemas detectados no projeto depois da varredura inicial.

No nosso exemplo, foram detectados vários problemas potenciais no manifesto de pacotes do app React Native. Uma vantagem é poder investigar as vulnerabilidades encontradas para saber mais sobre elas.
Na lista, Hermes-engine 0.5.1 tem uma vulnerabilidade conhecida que pode causar cross-site scripting (XSS). É possível mitigar o problema atualizando para uma versão posterior à 0.7.2, que já corrige essa vulnerabilidade.

Outra opção para verificar projetos React Native é fazer a varredura diretamente de um repositório, conectando sua conta Snyk ao repositório de código de sua preferência. A vantagem é que o Snyk pode fazer varreduras contínuas para detectar problemas em projetos com vários colaboradores, verificando o projeto a cada commit ou merge.
Para conectar seu repositório, crie uma conta Snyk. Depois, no painel do Snyk, clique na plataforma do repositório onde seu código está armazenado. Se a plataforma desejada não estiver no menu rápido, clique em Other e procure nas integrações de plataforma do Snyk.

Siga as etapas para conectar o repositório. Em seguida, na página de conexão, escolha o repositório que você quer verificar.

Clique no botão Add selected repositories e aguarde a conclusão da varredura. Uma grande vantagem é poder consultar os itens verificados e os resultados encontrados.

Assim como na varredura com a Snyk CLI, você pode consultar mais detalhes sobre a vulnerabilidade detectada e abrir uma solicitação automática de correção no repositório.

Você também pode integrar o Snyk ao editor de código de sua preferência para verificar automaticamente se há vulnerabilidades nas dependências enquanto desenvolve um app. Por exemplo, a extensão do Snyk para Visual Studio Code identifica possíveis vulnerabilidades não apenas no manifesto do pacote, mas também nos trechos do código que o utilizam.
Para concluir
À medida que os apps para dispositivos móveis passam a usar dados de forma mais sofisticada, proteger as informações dos usuários e os usuários finais se torna ainda mais essencial. Assim como acontece com aplicações web, apps React Native enfrentam os mesmos tipos de desafios de segurança, como transferência segura de dados, protocolos de autenticação e vulnerabilidades em dependências.
Confira esta lista de verificação com as práticas recomendadas de segurança para React para ajudar você e sua equipe a encontrar e corrigir problemas de segurança nas aplicações React.
Comece a participar de desafios de Capture the Flag
Aprenda a resolver desafios de Capture the Flag assistindo sob demanda ao nosso workshop virtual introdutório.
Kingsley Ubah é um desenvolvedor web full-stack experiente e redator técnico.



