5 práticas recomendadas de segurança para React com TypeScript
Marcelo Oliveira
8 de dezembro de 2022
0 minutos de leituraComo biblioteca voltada à criação de interfaces de usuário, e não um framework completo, o React permite que os desenvolvedores escolham as bibliotecas que preferirem para diferentes aspectos de uma aplicação, como roteamento, histórico e autenticação. Já o TypeScript foi criado pela Microsoft como uma extensão do JavaScript para adicionar tipagem estática opcional a uma linguagem que, de outra forma, tem tipagem fraca.
Usar TypeScript com React oferece várias vantagens no desenvolvimento de aplicações, como a possibilidade de criar componentes React mais simples e um suporte melhor a JavaScript XML (JSX) para validação de tipos estática. Como podemos usar componentes JavaScript em um projeto TypeScript, equipes de desenvolvimento com experiência em JavaScript podem aproveitar esse conhecimento para se beneficiar da programação com tipagem forte.
Há muitos boilerplates disponíveis para iniciar projetos React, incluindo Create React App, Create Next App, Vite, React Boilerplate e React Starter Kit.
O Create React App é uma ferramenta independente que pode ser executada com npm ou Yarn. Depois de instalada, podemos gerar e executar um novo projeto com apenas alguns comandos.
Primeiro, abra o terminal e execute o comando a seguir para instalar a ferramenta Create React App:
Em seguida, crie um projeto usando o template TypeScript com o executor de pacotes do Node (npx):
Outra opção é criar o projeto usando o gerenciador de pacotes Yarn:
possíveis riscos de segurança e como mitigá-los.
Ative o modo estrito
O modo estrito ativa automaticamente os parâmetros do compilador TypeScript relacionados às regras de tipos de dados. Quando o modo estrito do TypeScript está ativado, o código é validado de acordo com regras rigorosas de tipagem, obrigando os desenvolvedores a respeitar as limitações dos tipos de dados atribuídos a variáveis, constantes, parâmetros e valores de retorno de funções. O modo estrito é importante porque ajuda os desenvolvedores a encontrar e corrigir erros de incompatibilidade de tipos logo no início do desenvolvimento.
Imagine que uma aplicação tenha a seguinte função:
Chamamos a função deleteComment passando o argumento slug como string e commentId como número:
No entanto, nada nos impede de chamar a função com duas strings:
O código acima pode não ser permitido pelas regras de negócio, mas, como não especificamos os tipos, ambos os parâmetros são considerados do tipo padrão any. Por isso, o TypeScript não consegue nos ajudar a identificar o problema a menos que ativemos o modo estrito.
Novas aplicações React vêm com o valor de strict definido como true. No entanto, esse valor pode ser diferente em projetos existentes.
Para garantir que o projeto TypeScript esteja no modo estrito, abra o arquivo tsconfig.json e confira se o valor da configuração strict é true:
Volte à função deleteComment. Uma pequena alteração já gera erros de compilação do TypeScript:

Adicione os tipos string e number aos parâmetros de deleteComment:
Isso gera erros de compilação e impede os desenvolvedores de criar código cliente que chame a função deleteComment inadvertidamente com tipos inválidos, como no exemplo abaixo:

A opção strict ativa automaticamente outras opções recomendadas do compilador, relacionadas à verificação de tipos mais rigorosa.
Não use o tipo de retorno any em callbacks cujo valor será ignorado
Se você declarar o tipo de retorno de um callback como any e, sem querer, usar o valor retornado quando a função não retorna nada, pode cometer um erro que passará despercebido.
Considere uma função chamada onListFieldKeyUp que recebe como parâmetro um callback chamado onEnter:
Observe que a variável enterResult acima armazena o resultado da função de callback onEnter para uso posterior. Embora o callback não retorne nenhum valor, declaramos a variável enterResult com o tipo any, então o TypeScript não consegue alertar você sobre o problema.
Qual é a solução?
Primeiro, se você sabe que a função onEnter não retorna nenhum valor, substitua o tipo any no parâmetro do callback por void. Agora, o TypeScript exibe o erro “Uma expressão do tipo 'void' não pode ser testada quanto à veracidade.”

Por fim, remova o código que armazena o valor de retorno de onEnter na variável enterResult:
Ataques de renderização no lado do servidor em React
Uma aplicação web pode renderizar HTML no cliente ou no servidor. Frameworks e bibliotecas JavaScript modernos, como o React, adotam a renderização no lado do servidor. Essa abordagem traz ganhos de desempenho, incluindo o carregamento mais rápido das páginas: o back-end pode pré-renderizar rapidamente a página inteira e enviar o conteúdo estático de HTML, CSS e JavaScript para o front-end. Assim, os usuários podem navegar e visualizar a página web instantaneamente. Essa abordagem também ajuda na otimização para mecanismos de busca (SEO), pois páginas que carregam rapidamente têm pontuações mais altas nos algoritmos de busca.
Cross-site scripting (XSS) é um tipo de ataque em que invasores injetam scripts maliciosos do lado do cliente em uma página web. O React foi projetado para ser protegido contra XSS. No entanto, práticas de programação inadequadas e a renderização no lado do servidor em React podem gerar uma vulnerabilidade de XSS que será explorada por usuários mal-intencionados.
Por exemplo, nunca concatene dados não higienizados com a saída da função renderToStaticMarkup antes de enviar a string ao cliente:
O código acima não é seguro porque um invasor pode ter comprometido a variável someUnsanitizedData para incluir código JavaScript malicioso, como no exemplo a seguir:
Para evitar ataques de XSS, use um sanitizador de HTML, como o DomPurify.
Use tipos opacos
Um tipo de dado opaco impõe o ocultamento de informações. Sua estrutura de dados não é definida na interface, o que oculta e encapsula a implementação de um tipo de dado concreto. Módulos externos podem usar o tipo opaco sem acessar seus detalhes internos, enquanto funções internas com acesso às informações ocultas podem manipular o tipo. Os tipos opacos permitem alterar e evoluir detalhes internos sem mudar o código que os utiliza. Por isso, seu uso continua sendo uma prática recomendada de desenvolvimento.
Embora o TypeScript não ofereça tipos opacos nativamente, podemos implementá-los com facilidade. Vamos resolver um caso de uso real.
Imagine uma aplicação de comércio eletrônico que usa uma função em TypeScript para adicionar um produto ao carrinho do cliente:
Esses parâmetros tipados garantem que o programador não passe números ou outros tipos no lugar de strings para os parâmetros customerCode e productCode:
Embora não haja nada de errado com o código, o tipo não expressa os valores com precisão. Não dá para saber qual parâmetro é o código do cliente ou do produto apenas olhando a linha de código, e o TypeScript não emitirá um aviso se os valores forem trocados.
Agora veja como a função addToCart foi refatorada no exemplo abaixo para usar tipos opacos:
Graças aos novos tipos opacos e à validação com regex, o código gera um erro de compilação se você fornecer códigos incorretos:
Quando usar dangerouslySetInnerHTML e adotar práticas adequadas de sanitização
O React usa um DOM virtual como estratégia leve para atualizar o HTML da página com eficiência, evitando que os usuários precisem lidar diretamente com APIs nativas do navegador para manipular elementos HTML.
No entanto, às vezes você pode precisar substituir esse mecanismo e definir código HTML bruto nas aplicações React. Para manipular esse código HTML diretamente, o React usa uma propriedade especial de componente chamada dangerouslySetInnerHTML:
Como o nome sugere, a propriedade dangerouslySetInnerHTML deixa uma aplicação vulnerável quando não é usada corretamente. Invasores podem explorar aplicações que usam dangerouslySetInnerHTML para realizar ataques de cross-site scripting (XSS) e injetar scripts maliciosos disfarçados de entradas confiáveis de usuários no seu site.
Para evitar esse risco, sempre sanitize o conteúdo HTML antes de inseri-lo, removendo “impurezas” ou códigos maliciosos. Você pode usar uma biblioteca como DOMPurify e aplicar a função sanitize:
É importante lembrar que, como qualquer outra biblioteca, o DOMPurify pode apresentar vulnerabilidades de segurança ocasionalmente. Felizmente, a Snyk Vulnerability Database incorporou rapidamente os dados dessa vulnerabilidade e forneceu uma solução. Portanto, mesmo que uma biblioteca tenha um histórico sólido, ainda precisamos fazer a nossa parte e usar uma ferramenta como a Snyk para verificar periodicamente se há vulnerabilidades conhecidas.
E essa é apenas uma das preocupações de segurança que os desenvolvedores devem considerar. Neste vídeo, Liran Tal explica como desenvolvedores React podem cometer erros que levam a outras vulnerabilidades exploráveis por invasores.

Conclusão
Neste artigo, apresentamos algumas práticas recomendadas para desenvolver aplicações React com TypeScript, destacamos possíveis riscos de segurança e indicamos soluções.
O modo estrito permite impor restrições de tipos e detectar erros de incompatibilidade de tipos logo no início do desenvolvimento. Usar
voidem callbacks impede que os desenvolvedores usem um valor de retorno quando o callback não retorna nada.Ataques de injeção de comandos são uma ameaça séria à segurança. Evite criar código dinâmico com entradas suspeitas de usuários e use a função
execFileem vez deexec.Injeções de HTML também são uma ameaça séria à segurança. Ao usar
dangerouslySetInnerHTML, sempre sanitize a marcação inserida para impedir que invasores adulterem entradas de usuários e injetem códigos maliciosos.Por fim, os tipos opacos definem domínios significativos e ajudam você a validar tipos com mais facilidade e evitar duplicações.
É fácil usar TypeScript e React para criar aplicações rápidas e seguras, especialmente com frameworks como Create React App e aproveitando o conhecimento prévio de JavaScript.



