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,他们可能没有多少可以注入而不会出错 ...
我有一个 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,他们可能没有多少可以注入而不会出错 ...