强类型防坑:用 TypeScript 降低 OWASP 风险

产品经理小王 中级 7小时前 更新于 2026年7月26日 350 浏览 15 点赞 约 1 分钟

把数据库模型直接丢给 API 接口,或者把一个用户 ID 误传给租户 ID 参数,这种低级错误在大型项目里太常见了。虽然框架自带的安全检查很重要,但如果能在编译阶段就让代码“写不下去”错误逻辑,效率会高得多。

强类型防坑:用 TypeScript 降低 OWASP 风险

强类型不是万能药,它解决不了权限校验或 HTML 过滤,但能通过定义“边界”来减少漏洞。

1. 强制使用 DTO 隔离敏感数据

最怕的就是直接 res.json(user),万一哪天数据库加了个 password_hash 字段,分分钟全部泄露。建议定义严格的 DTO(数据传输对象)和映射函数。

type UserRow = {
 id: string;
 email: string;
 passwordHash: string;
 mfaSecret: string | null;
 internalNotes: string | null;
};

type PublicUserDto = {
 id: string;
 email: string;
};

function toPublicUser(user: UserRow): PublicUserDto {
 return { id: user.id, email: user.email };
}
// 永远不要在 HTTP 边界直接序列化 UserRow

2. 用 Branded Types 防止 ID 混淆

在 TS 里,所有的 ID 都是 string,这导致你很容易把 userId 传给需要 tenantId 的函数。可以用品牌类型(Branded Types)给字符串“打标签”。

declare const tenantBrand: unique symbol;
declare const userBrand: unique symbol;

type TenantId = string & { readonly [tenantBrand]: true };
type UserId = string & { readonly [userBrand]: true };

function loadUser(tenantId: TenantId, userId: UserId) {
 // 这样如果传反了,编译器直接报错,不用等到运行时才发现数据不对
}

3. 显式化权限上下文

不要在函数里传 isAdmin: boolean 这种模糊的参数,试着把权限状态定义为具体的类型。

type Viewer = { kind: "viewer"; userId: UserId };
type ProjectEditor = { kind: "project-editor"; userId: UserId; projectId: string };

type ProjectAccess = Viewer | ProjectEditor;

function renameProject(access: ProjectEditor, name: string) {
 // 只有持有 ProjectEditor 类型的对象才能调用此函数
}

这种做法本质上是把安全意图编码进了类型系统。不过得注意,Branded Types 在运行时会消失,所以外部输入在进入系统时必须经过严格的验证和类型转换。

AI编程AI编程实战programmingsecurityfunctional

全部回复 (4)

小Ray在路上 中级 12小时前
其实配合 Zod 做运行时校验才稳,不然 API 传错参数还是得崩。
0 回复
杭漂架构师 中级 11小时前
没错,单靠 TS 类型太虚了,你一般把 Zod 放在中间件里校验吗?
0 回复
杭漂码农 专家 12小时前
建议把 ID 都定义成品牌类型,这样就算都是字符串也传不混。
0 回复
技术宅Ray 初级 12小时前
确实,不过这种强类型定义多了,维护起来会不会很心累?
0 回复

发表回复

支持 Markdown 格式