拼接SQL字符串=高危入口,因Oracle不校验拼接后语句安全性;绑定变量USING是强制隔离机制,确保参数与SQL结构分离;表名列名等标识符需白名单校验,且校验须在拼接前完成。

拼接 SQL 字符串 = 把数据库执行权交给用户输入,没有例外
EXECUTE IMMEDIATE 拼字符串为什么立刻变高危入口
Oracle 不会对拼好的 sql_stmt 做任何“安全扫描”——它只管语法是否合法。一旦你写 lv_query := 'SELECT * FROM users WHERE id = ' || user_id,而 user_id 是 '1 OR 1=1 --',最终执行的就是 SELECT * FROM users WHERE id = 1 OR 1=1 --,整张表被拖走。
- ORA-00900、ORA-00917 这类错误常是注入已发生的信号,不是“语法写错了”,而是恶意内容已混入语句结构
- 空值参与拼接(
NULL || 'WHERE ...')会让整个sql_stmt变成NULL,运行时报ORA-06502 - 单引号没转义(比如
'O''Connor'写成'O'Connor')直接触发ORA-00917: missing comma
绑定变量 USING 不是优化项,是强制隔离机制
用 :1 占位符 + USING,Oracle 就把 SQL 文本和参数彻底分开:语句结构在解析阶段就固化,参数走独立通道,自动处理类型转换、空值、引号转义、长度截断。
- ✅ 正确:
lv_query := 'SELECT name FROM emp WHERE deptno = :1'; EXECUTE IMMEDIATE lv_query INTO rec USING dept_id; - ❌ 错误:
EXECUTE IMMEDIATE 'SELECT name FROM emp WHERE deptno = ' || dept_id INTO rec;(拼接即失守) - ⚠️ 注意:
USING后只能跟变量(如v_id),不能跟字面量(USING 123报错);多个相同值要重复传,比如IN (:1, :2)就得USING val, val
表名、列名这些结构化部分不能绑,但也不能裸拼
SELECT * FROM :table_name 语法非法,USING tab_var 无效。这类标识符必须拼接,但必须加白名单校验,不能靠正则“过滤单引号”这种伪防护。
- 查表是否存在:
SELECT COUNT(*) INTO cnt FROM user_tables WHERE table_name = UPPER(p_table_name) - 禁用含点号、双引号、斜杠的输入(防
schema.table或跨用户访问) - 拼接后务必用
DBMS_OUTPUT.PUT_LINE(sql_stmt)打印出来,手动粘贴到 SQL*Plus 验证语法
最常被忽略的一点:校验动作必须发生在拼接 sql_stmt 之前,而不是之后;且白名单必须是业务级穷举(IF p_table_name NOT IN ('orders', 'customers') THEN ...),不是“只允许字母数字”这种形同虚设的规则。

















