execute immediate必须配合using绑定变量,严禁拼接用户输入;表名列名等结构信息需用dbms_assert校验;in子句应采用member of或预设占位符;returning和bulk collect须严格匹配into子句。

EXECUTE IMMEDIATE必须配USING,拼字符串就是开后门
不加USING直接拼接用户输入,等于把SQL执行权交给攻击者。哪怕只是'SELECT * FROM emp WHERE name = ''' || user_name || '''',遇到user_name := 'x'' OR 1=1 --'就全表泄露。
Oracle 不校验拼完的字符串是否“合理”,只管执行——语法对就跑,不对就报ORA-00900或更隐蔽的逻辑错误。
-
USING让值和SQL结构彻底分离:语句文本固定,参数走独立通道,Oracle 自动处理空值、单引号转义、类型转换 - 占位符统一用
:1、:2位置式写法,避免命名混淆(:name虽可用,但顺序仍按出现位置匹配) -
USING后只能跟变量或表达式,不能跟字面量——USING 123会报错,得先v_id := 123; EXECUTE IMMEDIATE ... USING v_id
IN子句怎么绑变长列表?别硬拼LISTAGG
WHERE id IN (:a, :b, :c)看着方便,但参数个数不确定时必然崩:ORA-01008: not all variables bound。Oracle 不支持运行时动态展开绑定列表。
常见错误是试图USING my_list传一个数组,结果根本没生效。
- 安全做法一:用嵌套表 +
MEMBER OF,例如WHERE id MEMBER OF :id_list,绑定sys.odcinumberlist(1,2,3) - 安全做法二:预设最大长度(如最多10个),SQL写成
WHERE id IN (:1,:2,...,:10),未用项传NULL,再加AND id IS NOT NULL过滤 - 千万别用
LISTAGG拼字符串再INSTR查——绕开绑定=重回高危区
表名列名不能绑,但裸拼一样危险
EXECUTE IMMEDIATE 'SELECT * FROM ' || user_table是典型高危操作。攻击者填emp; DROP TABLE dept; --就能删表。
绑定变量只适用于值(WHERE条件、SET赋值等),不适用于对象名。这类“结构信息”必须拼接,但必须校验。
- 用
DBMS_ASSERT.SIMPLE_SQL_NAME(user_table)拦非法字符(含点、双引号、斜杠等) - 白名单兜底:查
USER_TABLES确认表存在,USER_TAB_COLUMNS核列名合法性 - 小写或数字开头的表名必须加双引号,如
"myTable",否则自动转大写后找不到
RETURNING和BULK COLLECT怎么配绑定变量?
RETURNING INTO和BULK COLLECT INTO不是可选装饰,而是强制配套项。漏掉就报错:ORA-06502或ORA-01422。
DML 动态语句不返回结果集,但能通过RETURNING拿回刚改的值;SELECT动态执行若不确定行数,INTO单变量必崩。
-
UPDATE带RETURNING必须用OUT修饰输出变量:EXECUTE IMMEDIATE 'UPDATE t SET x=:1 RETURNING y INTO :2' USING v1, OUT v2 - 查多行必须用
BULK COLLECT INTO配合集合类型,且初始化检查不能少:IF v_list.COUNT > 0 THEN ...前先确认v_list非NULL -
FORALL + EXECUTE IMMEDIATE不支持绑定,这种批量场景得换静态SQL或游标
关键点不在“会不会写”,而在“敢不敢信拼出来的字符串”。哪怕只拼一个表名,没校验就等于没防护。











