PostgREST、DRF 和 Go 的 database/sql 均非 SQL 注入免疫层,必须通过白名单校验字段名/操作符、禁用危险参数、强制使用占位符并拦截非法输入来防御。

PostgREST 不是 SQL 注入的“免疫层”,它只是翻译器。只要把未经验证的用户输入直接塞进查询参数(比如 select、filter、order),就等于给攻击者递了一把数据库钥匙。
为什么 PostgREST 的 eq 和 or 参数会成为注入入口?
PostgREST 把 URL 参数映射成 SQL 片段,但不校验字段名、操作符或嵌套结构是否合法。例如:
-
?name=eq.john'; DROP TABLE users; --这种写法本身会被 PostgREST 拒绝(因为单引号在 URL 中需编码,且 PostgREST 对值做基本转义),但攻击者会转向更隐蔽路径: -
?or=(id.gt.0,role.eq.admin)—— 利用or构造逻辑绕过 -
?select=id,role,custom_func(*)—— 调用未授权的自定义函数 -
?filter=profile->>'email'—— 滥用 JSON 操作符触发非预期解析
这些不是“SQL 字符串拼接”,而是利用 PostgREST 的表达式解析能力,把业务逻辑漏洞暴露为数据库权限漏洞。
- 所有动态字段名(如
select后的列名)必须来自白名单,不能由前端传入 - 所有操作符(
eq、gt、ilike等)必须显式限制范围,禁用cs、cd等低频/危险操作符 - 禁止用户控制
order的字段和方向(order=name.desc可能被用于盲注探测) - 对 JSON 路径(如
data->'user')做语法预检,拒绝含;、$、@的表达式
Django REST Framework 中 Serializer 怎么防注入?
DRF 的 Serializer 本身不防注入,它只做数据转换。真正起作用的是你是否主动调用 is_valid() 并拦截异常。
常见错误写法:
serializer = UserSerializer(data=request.data) serializer.save() # ❌ 跳过验证,直接入库
正确做法:
serializer = UserSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=400) # ✅ 拦截非法字段和格式
serializer.save()-
ModelSerializer默认允许所有模型字段,包括is_staff、password等敏感字段,必须用fields = ['name', 'email']显式声明 - 对于过滤场景(如
/users?role=admin),不要用request.query_params直接拼filter(**params),而应走django_filters.FilterSet或手动白名单校验 - 所有字符串类字段(尤其是
CharField)应设max_length和allow_blank=False,避免超长 payload 触发后端解析异常
Go 的 net/http + database/sql 如何避免参数污染?
Go 标准库不自动绑定 URL 查询参数到 SQL,所以风险不在框架,而在开发者是否手写拼接。
典型高危代码:
query := "SELECT * FROM users WHERE name = '" + r.URL.Query().Get("name") + "'"
rows, _ := db.Query(query) // ❌ 绝对禁止安全做法只有两条铁律:
所有用户输入必须经
db.Query/db.Exec的占位符接口传入,例如db.Query("SELECT * FROM users WHERE id = $1", id)-
若必须动态拼接字段名或操作符(如排序、多条件 OR 查询),只能从预设 map 查找,不能直译参数:
validOrders := map[string]bool{"name": true, "created_at": true} if !validOrders[orderField] { http.Error(w, "invalid order field", http.StatusBadRequest) return } database/sql的$1、?占位符仅适用于值,不适用于表名、字段名、ORDER BY 子句 —— 这些必须走白名单使用
pgx替代标准database/sql时,注意其QueryRow也支持命名参数(:name),但同样不覆盖标识符注入
PostgREST 的表达式解析、DRF 的序列化器、Go 的占位符,都不是银弹。真正起作用的,是你在每个请求入口处是否设置了那道“白名单+校验+拒绝”三重门。漏掉任意一环,攻击者就能顺着那条没关严的缝,摸到数据库里。


















