<h2>O Poder do Sistema de Tipos do TypeScript na Prevenção de Vulnerabilidades</h2>
<p>O TypeScript não é apenas uma ferramenta para adicionar tipos estáticos ao JavaScript — é um escudo preventivo contra uma classe inteira de vulnerabilidades de segurança. Quando você trabalha com tipos explícitos, força comportamentos seguros e elimina superfícies de ataque que existem naturalmente em código dinamicamente tipado. A verdade é que muitas vulnerabilidades comuns nascem da falta de clareza sobre o tipo e a forma dos dados que circulam pelo seu código.</p>
<p>Neste artigo, exploraremos como aproveitar o sistema de tipos do TypeScript para construir aplicações mais seguras. Não vamos apenas escrever código que "funciona" — vamos escrever código que <em>não pode falhar</em> da forma que esperamos. A diferença é fundamental: no primeiro caso, confiamos em testes; no segundo, confiamos na linguagem.</p>
<h2>Tipos Primitivos e Validação de Entrada</h2>
<h3>Compreendendo o Risco Real</h3>
<p>A validação de entrada é a primeira linha de defesa contra injeção de código, XSS, SQL injection e outros ataques. Em JavaScript puro, você nunca sabe realmente o tipo de um valor até tentar usá-lo. Em TypeScript, você <em>sabe</em>, desde o momento em que o código é escrito.</p>
<p>Considere um exemplo clássico: um endpoint que recebe dados de um usuário. Sem tipos, qualquer coisa entra. Com tipos, apenas o que você definir entra — e o compilador garante isso.</p>
<pre><code class="language-typescript"></code></pre>
<p>A diferença é sutil no código, mas profunda na segurança. O TypeScript verifica em tempo de compilação se você está passando os tipos corretos. Um atacante não pode forçar um string para dentro de um campo <code>number</code> — o servidor simplesmente rejeitará a requisição antes de qualquer lógica de negócio executar.</p>
<h3>Literal Types para Enumerações Seguras</h3>
<p>Quando você tem um conjunto finito e bem-definido de valores (como status de pedidos ou níveis de acesso), use literal types. Isso previne que valores inesperados circulem pelo seu código.</p>
<pre><code class="language-typescript"></code></pre>
<p>Literal types transformam valores em contratos. Não há negociação — ou você passa um valor válido, ou o código não executa.</p>
<h2>Tipos Opcionais e Null Safety</h2>
<h3>O Problema do Null Coalescing</h3>
<p>Um dos bugs mais comuns em produção é tentar acessar propriedades de <code>null</code> ou <code>undefined</code>. Em JavaScript, você só descobre em runtime. Em TypeScript com <code>strictNullChecks</code>, você descobre na compilação.</p>
<pre><code class="language-typescript"></code></pre>
<p>Ativar <code>strictNullChecks</code> no seu <code>tsconfig.json</code> é uma das mudanças mais impactantes que você pode fazer. Força seu time a lidar explicitamente com valores que podem ser ausentes, eliminando uma classe inteira de bugs.</p>
<h3>Non-null Assertion e seus Perigos</h3>
<p>Existe a tentation de usar <code>!</code> para "desabilitar" a verificação null. Evite isso quando possível — é uma abertura intencional em seu escudo de segurança.</p>
<pre><code class="language-typescript">// ⚠️ Usar com extrema cautela
interface Dados {
valor?: string;
}
const dados: Dados = obterDadosDoBancoDados();
// Isto compila porque você "prometeu" ao TypeScript que valor existe
const resultado = dados.valor!.toUpperCase();
// Mas se valor for undefined, você terá um erro em runtime
// Use apenas quando tiver 100% de certeza</code></pre>
<p>A única exceção legítima é quando você tem conhecimento de domínio que o TypeScript não consegue expressar — e mesmo assim, comente seu código explicando <em>por que</em> você sabe que é seguro.</p>
<h2>Tipos Genéricos e Sanitização de Dados</h2>
<h3>Criando Wrappers de Tipo para Dados Perigosos</h3>
<p>Em uma aplicação real, você trabalha com dados de múltiplas origens: APIs externas, formulários, cookies, headers HTTP. Nem todos são confiáveis. Você pode usar tipos genéricos para criar "wrappers" que explicitam quando um dado foi validado e quando não.</p>
<pre><code class="language-typescript"></code></pre>
<p>Este padrão força refatoração em todos os fluxos de dados. Qualquer valor que chegue da internet deve ser explicitamente validado antes de ser usado em operações sensíveis. Não é mágica — é discipline codificada no sistema de tipos.</p>
<h3>Tipos Distributivos para Sanitização</h3>
<p>Para casos onde você precisa sanitizar propriedades específicas de um objeto, tipos distributivos são poderosos:</p>
<pre><code class="language-typescript">// Remove campos sensíveis após sanitização
type SensitiveFields = "senha" | "token_api" | "cpf";
type Sanitized<T> = {
[K in keyof T]: K extends SensitiveFields ? never : T[K];
};
interface Usuario {
id: number;
nome: string;
email: string;
senha: string;
token_api: string;
}
function retornarParaFrontend(usuario: Usuario): Sanitized<Usuario> {
// TypeScript força você a remover os campos sensíveis
const { senha, token_api, ...seguro } = usuario;
return seguro as Sanitized<Usuario>;
}
// Se você tentar incluir um campo sensível, falha:
// return { ...usuario } as Sanitized<Usuario>; // ❌ Erro</code></pre>
<h2>Prevenção de Ataques Comuns Através de Tipos</h2>
<h3>CSRF e Validação de Estado</h3>
<p>Ataques CSRF funcionam porque um navegador enviará automaticamente cookies com qualquer requisição. Você pode usar o sistema de tipos para garantir que certas operações sensíveis sempre passam por validações específicas.</p>
<pre><code class="language-typescript"></code></pre>
<h3>XSS Prevention com Tipos de String Especializados</h3>
<p>Para aplicações que renderizam HTML no servidor ou no cliente, você pode criar tipos que marcam strings como "seguras" (já escapadas).</p>
<pre><code class="language-typescript"></code></pre>
<p>O compilador não deixará você renderizar HTML não-escapado. Ponto.</p>
<h2>Conclusão</h2>
<p>Aprendemos três lições fundamentais neste artigo. Primeiro: <strong>tipos explícitos são prevenção de bugs</strong>. Quando você define tipos rigorosos, elimina superfícies de ataque antes do código ser executado. O TypeScript verifica em compilação o que levaria horas de testes e debugging em JavaScript puro.</p>
<p>Segundo: <strong>null safety e validação de entrada são não-negociáveis</strong>. <code>strictNullChecks</code> força você a lidar com valores ausentes, e tipos genéricos como <code>Untrusted<T></code> e <code>Trusted<T></code> criam contratos que obrigam validação em pontos críticos. Não é burocracia — é segurança.</p>
<p>Terceiro: <strong>tipos especializados (branded types) codificam conhecimento de segurança</strong>. Em vez de confiar em comentários ou documentação, você força comportamentos seguros através do compilador. Um <code>CSRFToken</code> é diferente de uma <code>string</code> comum; HTML escapado é diferente de HTML bruto. Seu código se torna uma máquina de estados tipada que naturalmente segue as melhores práticas de segurança.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://www.typescriptlang.org/docs/handbook/2/narrowing.html" target="_blank" rel="noopener noreferrer">TypeScript Handbook - Strict Null Checks</a></li>
<li><a href="https://owasp.org/www-project-top-ten/" target="_blank" rel="noopener noreferrer">OWASP: Top 10 Web Application Security Risks</a></li>
<li><a href="https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/" target="_blank" rel="noopener noreferrer">TypeScript 5.0 Release Notes - Security Features</a></li>
<li><a href="https://egghead.io/articles/using-branded-types-in-typescript" target="_blank" rel="noopener noreferrer">Brand Types in TypeScript - Egghead.io</a></li>
<li><a href="https://learn.microsoft.com/en-us/windows/security/threat-protection/secure-coding-guidelines" target="_blank" rel="noopener noreferrer">Secure Coding Guidelines - Microsoft Security Development Lifecycle</a></li>
</ul>
<p><!-- FIM --></p>