Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在存储过程中使用分隔参数是否危险?_C#_Sql_Sql Server - Fatal编程技术网

C# 在存储过程中使用分隔参数是否危险?

C# 在存储过程中使用分隔参数是否危险?,c#,sql,sql-server,C#,Sql,Sql Server,我的C#面是这样的: if(Request.QueryString["ValuesFromUser"]!=null) { ValuesFromUser_ = Request["ValuesFromUser"]; } DataTable dtle = new DataTable(); SqlDataAdapter sqda; sqda = new SqlDataAdapter("Checkforuserinput", Connection); SqlParameter SQP = sqd

我的C#面是这样的:

if(Request.QueryString["ValuesFromUser"]!=null)
{
    ValuesFromUser_ = Request["ValuesFromUser"];
}

DataTable dtle = new DataTable();
SqlDataAdapter sqda;
sqda = new SqlDataAdapter("Checkforuserinput", Connection);
SqlParameter SQP = sqda.SelectCommand.Parameters.Add("@arg", SqlDbType.VarChar);
SQP.Direction = ParameterDirection.Input;
SQP.Value = "ValuesFromUser_";
sqda.Fill(dtle );
ALTER FUNCTION [dbo].[SplitDelimiterString] (@StringWithDelimiter VARCHAR(8000), @Delimiter VARCHAR(8))

RETURNS @ItemTable TABLE (Item VARCHAR(8000))

AS
BEGIN
    DECLARE @StartingPosition INT;
    DECLARE @ItemInString VARCHAR(8000);

    SELECT @StartingPosition = 1;
    --Return if string is null or empty
    IF LEN(@StringWithDelimiter) = 0 OR @StringWithDelimiter IS NULL RETURN; 

    WHILE @StartingPosition > 0
    BEGIN
        --Get starting index of delimiter .. If string
        --doesn't contain any delimiter than it will returl 0 
        SET @StartingPosition = CHARINDEX(@Delimiter,@StringWithDelimiter); 

        --Get item from string        
        IF @StartingPosition > 0                
            SET @ItemInString = SUBSTRING(@StringWithDelimiter,0,@StartingPosition)
        ELSE
            SET @ItemInString = @StringWithDelimiter;
        --If item isn't empty than add to return table    
        IF( LEN(@ItemInString) > 0)
            INSERT INTO @ItemTable(Item) VALUES (@ItemInString);            

        --Remove inserted item from string
        SET @StringWithDelimiter = SUBSTRING(@StringWithDelimiter,@StartingPosition + 
                     LEN(@Delimiter),LEN(@StringWithDelimiter) - @StartingPosition)

        --Break loop if string is empty
        IF LEN(@StringWithDelimiter) = 0 BREAK;
    END

    RETURN
END
用户将传递一些参数,如
“user1、user2、user3”

在我的sql端:

Create PROC [dbo].[Checkforuserinput] @arg VARCHAR(50)= 'All'
As
    Select * 
    from UserData 
    where User in (SELECT * 
                   FROM SplitDelimiterString(@Arg, ','))
SplitDelimiterString函数类似于:

if(Request.QueryString["ValuesFromUser"]!=null)
{
    ValuesFromUser_ = Request["ValuesFromUser"];
}

DataTable dtle = new DataTable();
SqlDataAdapter sqda;
sqda = new SqlDataAdapter("Checkforuserinput", Connection);
SqlParameter SQP = sqda.SelectCommand.Parameters.Add("@arg", SqlDbType.VarChar);
SQP.Direction = ParameterDirection.Input;
SQP.Value = "ValuesFromUser_";
sqda.Fill(dtle );
ALTER FUNCTION [dbo].[SplitDelimiterString] (@StringWithDelimiter VARCHAR(8000), @Delimiter VARCHAR(8))

RETURNS @ItemTable TABLE (Item VARCHAR(8000))

AS
BEGIN
    DECLARE @StartingPosition INT;
    DECLARE @ItemInString VARCHAR(8000);

    SELECT @StartingPosition = 1;
    --Return if string is null or empty
    IF LEN(@StringWithDelimiter) = 0 OR @StringWithDelimiter IS NULL RETURN; 

    WHILE @StartingPosition > 0
    BEGIN
        --Get starting index of delimiter .. If string
        --doesn't contain any delimiter than it will returl 0 
        SET @StartingPosition = CHARINDEX(@Delimiter,@StringWithDelimiter); 

        --Get item from string        
        IF @StartingPosition > 0                
            SET @ItemInString = SUBSTRING(@StringWithDelimiter,0,@StartingPosition)
        ELSE
            SET @ItemInString = @StringWithDelimiter;
        --If item isn't empty than add to return table    
        IF( LEN(@ItemInString) > 0)
            INSERT INTO @ItemTable(Item) VALUES (@ItemInString);            

        --Remove inserted item from string
        SET @StringWithDelimiter = SUBSTRING(@StringWithDelimiter,@StartingPosition + 
                     LEN(@Delimiter),LEN(@StringWithDelimiter) - @StartingPosition)

        --Break loop if string is empty
        IF LEN(@StringWithDelimiter) = 0 BREAK;
    END

    RETURN
END
对于SQL注入,此代码是安全的还是有风险的

或者我应该使用这个:

Create PROC [dbo].[Checkforuserinput] @arg VARCHAR(50)= 'All'
As
    declare @query nvarchar(max)
    set @query = 'Select * from UserData where User in ('+@Arg+')'
    EXECUTE sp_executesql @query 

根据您的SQLServer版本,您可能需要考虑将表值参数传递给存储过程。 表值参数提供了一种将多行数据从客户端应用程序封送到SQL Server的简单方法,无需多次往返或特殊的服务器端逻辑来处理数据。您可以使用表值参数封装客户端应用程序中的数据行,并在单个参数化命令中将数据发送到服务器。SqlParameter通过使用AddWithValue方法填充,SqlDbType设置为Structured

以下链接提供了一个良好的概述:


我看不出split函数存在任何可预见的问题,但传递表值参数会更有效

SQL

C#

编写一个helper函数,将任何
IEnumerable(string)
写入SQL Server能够理解的
DataTable

public static class SqlExtensions
{
    public static DataTable ToSqlArray(this IEnumerable<string> collection)
    {
        var dt = new DataTable("ArrayOfString");
        dt.Columns.Add(new DataColumn("Item", typeof(string)));

        foreach(var item in collection)
        {
            var row = dt.NewRow();
            row[0] = item;
            dt.Rows.Add(row);
        }

        return dt;
    }
}

分割功能肯定更好。最坏的情况是,它应该在您的C#命令调用中抛出异常。第二种方法适合SQL注入。另外,请注意,如果合适的话,您可以将该函数的结果进行内部联接,而不是使用子查询(这会快得多,但如果您的数据允许的话,它可能会得到多行),没有任何东西可以阻止某人将类似于
user1,'drop table UserData
(或类似的内容)的内容传递到查询中。快速浏览一下,您的分割函数看起来很好。