引言:为什么TypeScript应用程序的安全性从第一天起就至关重要
TypeScript 是 JavaScript 的超集,它添加了静态类型。许多初学者错误地认为类型化会自动解决所有安全问题。实际上,TypeScript 会被编译成普通的 JavaScript,所有 JS 固有的漏洞仍然存在。在本文中,我们将分析初学者遇到的十大漏洞,并展示如何避免它们。
1. XSS(跨站脚本攻击)
XSS 是最常见的攻击之一。攻击者将恶意脚本注入页面,该脚本在用户的浏览器中执行。
漏洞代码示例:
function renderUserInput(input: string): string { return `<div>${input}</div>`;}
// 攻击者传入:<script>alert('XSS')</script>如何修复:
始终对用户输入进行转义。使用像 DOMPurify 这样的库或内置的转义方法:
import DOMPurify from 'dompurify';
function safeRender(input: string): string { const clean = DOMPurify.sanitize(input); return `<div>${clean}</div>`;}2. SQL 注入
如果你通过拼接字符串和用户输入来构建 SQL 查询,你就为 SQL 注入打开了大门。
漏洞代码:
function getUser(username: string): Promise<User> { const query = `SELECT * FROM users WHERE username = '${username}'`; return db.execute(query);}安全版本:
function getUserSafe(username: string): Promise<User> { const query = 'SELECT * FROM users WHERE username = $1'; return db.execute(query, [username]); // 参数化查询}3. 不安全的密码存储
永远不要以明文形式存储密码。使用 bcrypt 或 argon2 进行哈希处理。
import bcrypt from 'bcrypt';
async function hashPassword(password: string): Promise<string> { const saltRounds = 12; return bcrypt.hash(password, saltRounds);}
async function verifyPassword(password: string, hash: string): Promise<boolean> { return bcrypt.compare(password, hash);}4. 不安全的直接对象引用 (IDOR)
当用户只需更改 URL 中的 ID 就能访问他人的数据时。
示例:
// 有漏洞:任何用户都可以获取任何订单app.get('/api/order/:id', (req, res) => { const order = getOrderById(req.params.id); res.json(order);});
// 安全:检查所有权app.get('/api/order/:id', (req, res) => { const order = getOrderById(req.params.id); if (order.userId !== req.user.id) { return res.status(403).json({ error: 'Forbidden' }); } res.json(order);});5. 使用过时的依赖项
TypeScript 项目经常使用 npm 包。过时的版本可能包含已知漏洞。
- 定期运行
npm audit - 使用
npm update更新包 - 在 CI/CD 中配置自动检查
6. 输入数据验证不足
TypeScript 类型在运行时不会被检查。始终在服务器端验证数据。
interface UserInput { email: string; age: number;}
// 不足:TypeScript 类型在运行时无法保护function processUser(input: UserInput) { // ...}
// 正确:使用 Zod 或 Joi 进行验证import { z } from 'zod';
const UserSchema = z.object({ email: z.string().email(), age: z.number().min(18).max(120)});
function processUserSafe(input: unknown) { const validate