Postgres同时使用预编译语句和字符转义能否抵御恶意输入攻击?
问题核心漏洞
你这套写法本质上完全没有正确利用预编译语句的安全防护能力:你只是预编译了查询模板,最后执行时依然手动拼接参数到SQL字符串中,和直接拼接SQL没有本质区别,仅靠转义单引号的防护非常脆弱,存在明确的注入风险。
可行注入方式
就算你做了单引号转义,也可以通过空字节截断实现注入,只需要让function_that_returns_user_input_string()返回如下内容即可:
任意内容\x00'); DROP TABLE myschema.mytable;--
攻击原理:
PostgreSQL解析字符串时遇到空字节(\x00)会直接截断字符串内容,你转义后的参数拼接到SQL中后结构如下:
EXECUTE mystatement ('任意内容\x00''); DROP TABLE myschema.mytable;--');
数据库读到\x00时就认为参数的字符串已经结束,后面的'); DROP TABLE...会被当成独立的SQL语句执行,直接删除目标表。
除此之外如果数据库客户端使用GBK等多字节编码,还可以通过宽字节注入绕过单引号转义防护,不需要空字节也能完成注入。
替换为INSERT语句的影响
完全不会改变存在注入风险的结论。只要你还是保持手动拼接EXECUTE参数的写法,不管是SELECT、INSERT、UPDATE还是DELETE语句,都可以通过同样的思路构造注入 payload,比如INSERT场景下可以构造payload插入管理员权限账号、篡改业务数据,也可以直接用堆叠查询执行删库、提权等恶意操作。
正确的防护写法
完全不需要自己做单引号转义,直接用数据库驱动的参数绑定能力传参即可:
# 错误写法:手动拼接参数 # cursor.execute(f"EXECUTE mystatement ('{modified_input}');") # 正确写法:通过驱动绑定参数 cursor.execute("EXECUTE mystatement (%s)", (user_input,))
这种写法下参数会被驱动单独处理,完全不会被解析为SQL语法的一部分,从根源上避免SQL注入风险。
内容的提问来源于stack exchange,提问作者JCollier
相关产品推荐
相关产品推荐

