TypeScript 应用安全:面向初学者的十大漏洞
\n\nTypeScript 是 JavaScript 的超集,它添加了静态类型检查,但并不能防御经典的 Web 漏洞。初学者开发者常常依赖类型严格性,却忽视了逻辑和数据层面的安全性。在本文中,我们将通过代码示例和防护方法,剖析 TypeScript 应用中最常见的 10 个漏洞。
\n\n1. 通过 dangerouslySetInnerHTML 导致的 XSS(跨站脚本攻击)
\n最常见的问题之一是在未进行清理的情况下插入用户提供的 HTML。在 TypeScript 中,这常见于使用 React 或 Angular 时。
\n\n// ❌ 有漏洞的代码\nfunction UserComment({ comment }: { comment: string }) {\n return <div dangerouslySetInnerHTML={{ __html: comment }} />;\n}\n\n// ✅ 安全版本\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. 通过字符串查询导致的 SQL 注入
\n如果您使用原始字符串,TypeScript 无法防御 SQL 注入。请始终使用参数化查询。
\n\n// ❌ 危险\nconst query = `SELECT * FROM users WHERE email = '${userEmail}'`;\n\n// ✅ 安全(以 Prisma 为例)\nconst user = await prisma.user.findUnique({\n where: { email: userEmail }\n});\n\n3. 在代码中不安全地存储机密信息
\nAPI 密钥、令牌和密码不应出现在源代码中。TypeScript 会编译为 JavaScript,所有字符串仍然可读。
\n\n// ❌ 永远不要这样做\nconst API_KEY = 'sk-1234567890abcdef';\n\n// ✅ 使用环境变量\nconst API_KEY = process.env.API_KEY;\nif (!API_KEY) throw new Error('API_KEY is missing');\n\n4. NoSQL 注入(MongoDB)
\n在使用 Mongoose 或驱动程序操作 MongoDB 时,可能会意外传递一个操纵逻辑的查询对象。
\n\n// ❌ 有漏洞的代码\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// ✅ 安全版本\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(跨站请求伪造)
\n如果您的应用使用 Cookie 认证,攻击者可以代表用户执行操作。
\n\n// ❌ 缺少防护\napp.post('/transfer', (req, res) => {\n // 执行转账,未验证来源\n});\n\n// ✅ 通过 CSRF 令牌进行防护(以 csurf 为例)\nimport csrf from 'csurf';\nconst csrfProtection = csrf({ cookie: true });\napp.post('/transfer', csrfProtection, (req, res) => {\n // 安全执行\n});\n\n6. 原型污染
\n在未经验证的情况下合并对象可能会覆盖原型属性,从而导致漏洞。
\n\n// ❌ 危险\nfunction merge(target: any, source: any) {\n for (const key in source) {\n target[key] = source[key];\n }\n}\n\n// ✅ 安全\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. 通过错误信息泄露信息
\n堆栈跟踪和数据库详细信息不应向用户显示。TypeScript 的严格类型可能会降低警惕性。
\n\n// ❌ 不好\napp.use((err, req, res, next) => {\n res.status(500).json({ error: err.m