graphql层无法自动拦截sql注入,必须在解析器中使用参数化查询;pg_graphql虽底层预编译免疫注入,但仍需手动配置rls和权限,且resolver中须避免raw()等拼接陷阱。

GraphQL层无法自动拦截SQL注入,必须在解析器里做参数化
GraphQL本身不执行SQL,它只负责解析查询、调用解析器函数。真正执行数据库操作的是你写的resolvers。如果解析器里拼接了用户输入到SQL字符串中(比如WHERE name = '${args.name}'),那和传统Web应用一样会触发SQL注入。
常见错误现象:前端传入name: "admin' OR '1'='1",后端直接插进SQL,结果绕过条件查出所有数据。
- 所有数据库操作必须使用参数化查询——PostgreSQL用
$1占位符,MySQL用?,SQLite用?或命名参数 - 避免任何
string + user_input拼接SQL的写法,包括ORDER BY、IN子句等动态部分 - 对非字符串字段(如
id、status)也需校验类型和范围,不能只靠“看起来像数字”就放行
pg_graphql这类原生方案自带SQL注入防护,但权限配置仍需手动
如果你用的是pg_graphql(PostgreSQL扩展直曝GraphQL),它底层用的是预编译语句,所有参数都走libpq绑定,天然免疫SQL注入。但这不等于安全了——它把权限控制完全交给了PostgreSQL本身。
容易踩的坑是:误以为“用了pg_graphql就不用管SQL安全”,结果忘了配RLS(行级安全)或撤掉表权限。
-
REVOKE SELECT ON public.users FROM api_user;能直接让users类型从GraphQL Schema里消失 -
CREATE POLICY必须显式定义,否则即使参数安全,用户也能读取全表 - JWT claims需要映射到PostgreSQL角色,否则
current_user始终是固定角色,RLS失效
resolver里用ORM/Query Builder时,警惕“伪参数化”陷阱
很多开发者以为用了Prisma、Drizzle或Knex就算安全了,其实不然。这些工具在某些场景下仍会触发拼接风险。
典型问题:Knex的.whereRaw()、Prisma的raw()、Drizzle的sql`...`模板字面量,如果里面混入未过滤的args,照样中招。
- Prisma:避免
prisma.user.findMany({ where: { name: { contains: args.search } } })之外的手动raw() - Knex:用
.where('name', 'like', `%${args.search}%`),而不是.whereRaw("name LIKE '%?%'", [args.search]) - Drizzle:优先用
eq(users.name, args.name)等类型安全方法,而非sql`...`拼接
GraphQL参数校验不是可选项,而是第一道防线
即便解析器用了参数化查询,未经校验的args仍可能被用于其他危险操作——比如构造文件路径、调用外部API、触发系统命令。GraphQL的String、Int类型只做基础转换,不做过滤。
例如filter: String!字段,传"'; DROP TABLE users; --"不会被GraphQL拒绝,但可能被解析器误用。
- 在schema定义阶段就加
@constraint指令(如directive @constraint(minLength: 1, maxLength: 50)),配合graphql-constraint-directive库生效 - 在resolver入口处做白名单校验:对
orderBy字段只允许["name", "created_at"],禁止传"password ASC" - 对模糊搜索类参数(如
search)主动过滤/[;'"\-]/g等SQL元字符,哪怕底层是参数化
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











