不能直接拼接字符串执行Oracle动态SQL,因易引发SQL注入;必须用Parameters.Add绑定值参数,表名列名等对象名需白名单校验,且连接状态和游标释放不可忽略。

为什么不能直接拼接字符串执行 Oracle 动态 SQL
因为 OracleCommand.CommandText 拼接用户输入会触发 SQL 注入,哪怕加了单引号包裹也不安全——Oracle 支持 EXECUTE IMMEDIATE 中嵌套引号逃逸、绑定变量绕过、甚至利用 UTL_INADDR 等包发起外联攻击。ODP.NET 的绑定机制不是“语法糖”,而是服务端预编译的强制路径。
用 OracleCommand + Parameters.Add 替代字符串拼接
动态 SQL 仍可使用绑定变量,但需注意:表名、列名、排序字段等**对象名无法参数化**,必须白名单校验或正则过滤;而值类参数(WHERE name = :val)必须走 Add() 方法。
-
OracleCommand的CommandType设为CommandType.Text(默认),不要设成StoredProcedure - 所有值参数统一用冒号前缀(如
:user_id),调用Parameters.Add(":user_id", OracleDbType.Int32).Value = 123 - 避免混用问号占位符(ODP.NET 不支持问号式绑定,只认冒号命名)
- 若 SQL 含多个同名参数(如多次用
:status),ODP.NET 会复用同一个参数值,无需重复添加
处理运行时变化的列名或表名
这类元数据必须在拼接前做严格约束,不能依赖前端传入或配置文件直读。常见做法:
- 用预定义字典映射合法表名:
var validTables = new HashSet<string> { "orders", "customers" };</string>,检查inputTable是否在其中 - 列名用枚举转字符串:
public enum SortField { OrderDate, TotalAmount },再通过Enum.GetName(typeof(SortField), field)转换 - 排序方向限定为
"ASC"或"DESC"字符串,禁止拼接任意字符串到ORDER BY ... [dir] - 绝对不要对表名/列名调用
OracleCommand.Parameters.Add—— 这会报错或被忽略
警惕 ExecuteNonQuery 和 ExecuteReader 的隐式事务行为
ODP.NET 默认不自动开启事务,但动态 SQL 若含 DML(INSERT/UPDATE/DELETE),需显式控制提交逻辑,否则可能造成连接挂起或锁等待。
- 执行前确认
OracleConnection.State == ConnectionState.Open,未打开时ExecuteNonQuery会抛InvalidOperationException - 涉及多条语句(如
BEGIN ... END块),用ExecuteNonQuery即可;若需返回结果集,必须用ExecuteReader,且不能混用 - 批量执行多个动态 SQL 时,建议封装在
OracleTransaction中,避免部分成功部分失败 - 使用
using包裹OracleCommand和OracleDataReader,防止游标泄露(Oracle 服务端资源不会自动回收)


















