Oracle:在无法使用参数时防止 SQL 注入的正确方法

Oracle: correct way to prevent SQL Injection when using parameters is not possible

我有一个 C# 程序可以对 Oracle 数据库执行一些操作。操作之一——创建一个新帐户。

CREATE USER {login} IDENTIFIED BY {password}

问题是我不能在这里使用Parameters,因为这种类型的查询不支持。我没有找到关于为什么不支持它的确切文档,但我想它类似于此处描述的内容(DDL 操作不支持参数):How to use SqlCommand to CREATE DATABASE with parameterized db name?

所以我的问题是 - 如何在 Oracle 中具体防止 SQL 注入?是否应该使用一些正则表达式来验证登录名和密码?如果是这样,它会是什么?不清楚,因为,作为 Oracle 文档 says “非引号标识符不能是 Oracle SQL 保留字。引号标识符可以是保留字,尽管不推荐这样做。” 如何检查我的登录名不是任何保留字?等等。

MS SQL 我也有类似情况

CREATE LOGIN {login} WITH PASSWORD=N'{password}'

我正在通过以下方式解决它:我用

逃避登录
new SqlCommandBuilder().QuoteIdentifier(name);

和简单的密码

password.Replace("'", "''");

因为它是查询中的文字。

我认为在这种情况下您可以使用 DBMS_ASSERT,下面是一个使用 DBMS_ASSERT 检查用户名的存储过程示例:

create or replace procedure procedure_create_user
   (user_name IN varchar2 , u_password IN varchar2 )
  IS
    tmp_query varchar(150);
    user_name_upper varchar(30) := UPPER(user_name) ;
  BEGIN
    tmp_query := 'create user C##' || dbms_assert.simple_sql_name(user_name_upper) || ' identified by ' || u_password;
    EXECUTE IMMEDIATE ( tmp_query );

    tmp_query := 'grant create session to C##' || user_name_upper ;
    EXECUTE IMMEDIATE ( tmp_query );
  END;
  /

然后您可以调用此过程并创建用户:

exec procedure_create_user('alessio', 'llll');

在 C# 中,您应该能够以这种方式调用存储过程:

 using (OracleConnection connection = new OracleConnection("ConnectionString"))
    using (OracleCommand command = new OracleCommand("procedure_create_user", connection))             
    {
          command.CommandType = CommandType.StoredProcedure;
          command.Parameters.Add("user_name", OracleDbType.Varchar2).Value = "alessio";
          command.Parameters.Add("u_password", OracleDbType.Varchar2).Value = "llll";

          connection.Open();
          command.ExecuteNonQuery();
    }

对于密码字段你应该做同样的事情,但如果你想允许一些 simple_sql_name 不允许的字符,你需要小心......可能没有必要密码,因为即使它们是注入代码,它们也不应该造成太大的伤害,因为在识别部分(IDENTIFIED BY)之后,CREATE USER 过程应该只接受一组有限的关键字,所以如果您之后甚至设置了 PASSWORD EXPIRE,他们可能没有多少可以注入而不会出错 ...