我有一个变量,它是一个字符串数组。我想传递变量的所有值,将变量的所有元素串联到单个字符串中。
但是我不确定这是否会带来SQL注入的风险。 我的代码:
private string concatenateStrings(string[] sa)
{
StringBuilder sb = new StringBuilder();
foreach (string s in sa)
{
if (sb.Length > 0)
{
sb.Append(",");
}
sb.Append("'");
sb.Append(s);
sb.Append("'");
}
return sb.ToString();
}
public void UpdateClaimSts(string[] ids)
{
string query = @"UPDATE MYTABLE
SET STATUS = 'X'
WHERE TABLEID in (" + concatenateStrings(ids) + ")";
OracleCommand dbCommand = (OracleCommand)this.Database.GetSqlStringCommand(query) as OracleCommand;
this.Database.ExecuteNonQuery(dbCommand, this.Transaction);
}
我尝试将查询更改为使用参数化查询:
string query = @"UPDATE MYTABLE
SET STATUS = 'X'
WHERE TABLEID in (:ids)";
OracleCommand dbCommand = (OracleCommand)this.Database.GetSqlStringCommand(query) as OracleCommand;
dbCommand.Parameters.Add(":ids", OracleType.VarChar).Value = concatenateStrings(ids);
this.Database.ExecuteNonQuery(dbCommand, this.Transaction);
但是它不起作用。有什么想法吗?
答案 0 :(得分:3)
像这样创建一个PL / SQL过程(在PL / SQL包内部):
TYPE TArrayOfVarchar2 IS TABLE OF MYTABLE.TABLEID%TYPE INDEX BY PLS_INTEGER;
PROCEDURE UPDATE_MYTABLE(TABLEIDs IN TArrayOfVarchar2) IS
BEGIN
FORALL i IN INDICES OF TABLEIDs
UPDATE MYTABLE SET STATUS = 'X' WHERE TABLEID = TABLEIDs(i);
END;
并拨打这样的电话:
using (OracleCommand cmd = new OracleCommand("BEGIN UPDATE_MYTABLE(:tableId); END;"), con))
{
cmd.CommandType = CommandType.Text;
// or
// OracleCommand cmd = new OracleCommand("UPDATE_MYTABLE"), con);
// cmd.CommandType = CommandType.StoredProcedure;
var par = cmd.Parameters.Add("tableId", OracleDbType.Varchar2, ParameterDirection.Input);
par.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
par.Value = sa;
par.Size = sa.Length;
cmd.ExecuteNonQuery();
}
答案 1 :(得分:1)
作为一种快速且局部的 (我们假设TABLEID
字段为NUMBER
类型)解决方案,您可以验证{{ 1}}是有效整数:
sa
一般情况下,您可以尝试使用绑定变量(请注意 plural :我们必须创建许多 ):< / p>
private string concatenateStrings(string[] sa) {
return string.Join(", ", sa
.Where(item => Regex.IsMatch(item, @"^\-?[0-9]+$")));
}
public void UpdateClaimSts(string[] ids) {
string query = string.Format(
@"UPDATE MYTABLE
SET STATUS = 'X'
WHERE TABLEID IN ({0})", concatenateStrings(ids));
...
答案 2 :(得分:0)
C#具有OracleCollectionType.PLSQLAssociativeArray
类型,用于将数组传递给PL / SQL关联数组数据类型,但是由于它只是一个PL / SQL数据结构,因此不能在SQL查询中使用。
不幸的是,它不支持将数组传递给SQL Collection数据类型(可以在SQL查询中使用)。
一种解决方法是让您的DBA创建一个简单的函数,将PL / SQL关联数组转换为SQL集合,然后将其用作查询的中间步骤:
CREATE TYPE varchar2s_array_type IS TABLE OF VARCHAR2(100)
/
CREATE PACKAGE utils IS
TYPE varchar2s_assoc_array_type IS TABLE OF VARCHAR2(100) INDEX BY PLS_INTEGER;
FUNCTION assoc_array_to_collection(
p_assoc_array IN varchar2s_assoc_array_type
) RETURN varchar2s_array_type DETERMINISTIC;
END;
/
CREATE PACKAGE BODY utils IS
FUNCTION assoc_array_to_collection(
p_assoc_array IN varchar2s_assoc_array_type
) RETURN varchar2s_array_type DETERMINISTIC
IS
p_array varchar2s_array_type := varchar2s_array_type();
i PLS_INTEGER;
BEGIN
IF p_assoc_array IS NOT NULL THEN
i := p_assoc_array.FIRST;
LOOP
EXIT WHEN i IS NULL;
p_array.EXTEND();
p_array(p_array.COUNT) := p_assoc_array(i);
i := p_assoc_array.NEXT(i);
END LOOP;
END IF;
RETURN p_array;
END;
END;
/
然后,您可以在SQL语句中更改代码以使用MEMBER OF
而不是IN
:
UPDATE MYTABLE
SET STATUS = 'X'
WHERE TABLEID MEMBER OF utils.assoc_array_to_collection(:ids)
并使用类似的方式绑定参数(我不是C#用户,所以即使语法不完全正确,这也只是为了让您大致了解该方法):< / p>
var par = cmd.Parameters.Add(":ids", OracleDbType.Varchar2, ParameterDirection.Input);
par.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
par.Value = ids;
par.Size = ids.Length;
cmd.ExecuteQuery();
然后,您可以在许多查询中重用通用函数。