Segurança de aplicações TypeScript: top-10 vulnerabilidades para iniciantes
\n\nTypeScript é uma extensão do JavaScript que adiciona tipagem estática, mas não protege contra vulnerabilidades web clássicas. Desenvolvedores iniciantes frequentemente confiam na rigidez dos tipos, esquecendo-se da segurança no nível da lógica e dos dados. Neste artigo, analisaremos as 10 vulnerabilidades mais comuns em aplicações TypeScript com exemplos de código e métodos de proteção.
\n\n1. XSS (Cross-Site Scripting) via dangerouslySetInnerHTML
\nUm dos problemas mais frequentes é a inserção de HTML do usuário sem sanitização. Em TypeScript, isso é comum ao trabalhar com React ou Angular.
\n\n// ❌ Código vulnerável\nfunction UserComment({ comment }: { comment: string }) {\n return <div dangerouslySetInnerHTML={{ __html: comment }} />;\n}\n\n// ✅ Versão segura\nimport DOMPurify from 'dompurify';\n\nfunction SafeComment({ comment }: { comment: string }) {\n const sanitized = DOMPurify.sanitize(comment);\n return <div dangerouslySetInnerHTML={{ __html: sanitized }} />;\n}\n\n2. Injeções SQL via consultas em string
\nTypeScript não protege contra injeções SQL se você usar strings brutas. Sempre use consultas parametrizadas.
\n\n// ❌ Perigoso\nconst query = `SELECT * FROM users WHERE email = '${userEmail}'`;\n\n// ✅ Seguro (exemplo com Prisma)\nconst user = await prisma.user.findUnique({\n where: { email: userEmail }\n});\n\n3. Armazenamento inseguro de segredos no código
\nChaves de API, tokens e senhas não devem estar no código-fonte. TypeScript compila para JavaScript e todas as strings permanecem legíveis.
\n\n// ❌ Nunca faça isso\nconst API_KEY = 'sk-1234567890abcdef';\n\n// ✅ Use variáveis de ambiente\nconst API_KEY = process.env.API_KEY;\nif (!API_KEY) throw new Error('API_KEY is missing');\n\n4. Injeções NoSQL (MongoDB)
\nAo trabalhar com MongoDB via Mongoose ou driver, você pode acidentalmente passar um objeto de consulta que manipula a lógica.
\n\n// ❌ Código vulnerável\napp.post('/login', async (req, res) => {\n const user = await User.findOne({ \n email: req.body.email, \n password: req.body.password \n });\n});\n\n// ✅ Versão segura\napp.post('/login', async (req: Request, res: Response) => {\n const { email, password } = req.body;\n if (typeof email !== 'string' || typeof password !== 'string') {\n return res.status(400).send('Invalid input');\n }\n const user = await User.findOne({ email, password });\n});\n\n5. CSRF (Cross-Site Request Forgery)
\nSe sua aplicação usa autenticação por cookie, um atacante pode executar ações em nome do usuário.
\n\n// ❌ Sem proteção\napp.post('/transfer', (req, res) => {\n // Executa transferência sem verificar a origem\n});\n\n// ✅ Proteção via token CSRF (exemplo com csurf)\nimport csrf from 'csurf';\nconst csrfProtection = csrf({ cookie: true });\napp.post('/transfer', csrfProtection, (req, res) => {\n // Execução segura\n});\n\n6. Prototype Pollution (poluição de protótipos)
\nAo mesclar objetos sem validação, é possível sobrescrever propriedades do protótipo, levando a vulnerabilidades.
\n\n// ❌ Perigoso\nfunction merge(target: any, source: any) {\n for (const key in source) {\n target[key] = source[key];\n }\n}\n\n// ✅ Seguro\nfunction safeMerge(target: Record<string, any>, source: Record<string, any>) {\n for (const key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n target[key] = source[key];\n }\n }\n}\n\n7. Vazamento de informações através de erros
\nStack traces e detalhes do banco de dados não devem ser exibidos ao usuário. TypeScript pode dar uma falsa sensação de segurança devido à tipagem forte.
\n\n// ❌ Ruim\napp.use((err, req, res, next) => {\n res.status(500).json({ error: err.m