当字符串有数字时,程序被破坏

时间:2013-12-09 13:57:42

标签: c# asp.net sql-server visual-studio-2010

我在SQL Server中编写了这个过程:

ALTER proc [dbo].[cazacliente2]
    (@vbusca nvarchar(60), @bo int) 
as
   if  @bo= 1  
   begin
      select idcliente, nome, endere, tel, pedido from Vw_Conscliente
      where  nome like @vbusca  
   end

   if @bo = 2
   begin 
      select idcliente, nome, endere, tel, pedido from Vw_Conscliente
      where endere like @vbusca 
   end

   if @bo = 3
   begin 
      select idcliente, nome, endere, tel, pedido from Vw_Conscliente
      where tel like  @vbusca  
   end

   if @bo = 4
   begin
      select idcliente, nome, endere, tel, pedido from Vw_Conscliente
      where pedido like @vbusca
   end

和asp.net中的代码:

  {
        string valorC = "%" + TextBox1.Text + "%"; numo = DropDownList1.SelectedValue;
        string valorB = valorC.Replace(" ", "%"); 

        switch (numo)
        { 
            case "Nome":  num3 = 1;  break;     case "Endereço": num3 = 2; break ;
            case "Telefone": num3 = 3 ; break;  case "Pedido": num3 = 4; break ;
        }

        SqlCommand cmd = new SqlCommand();
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.CommandText = "cazacliente2";
        SqlParameter valor = new SqlParameter("@vbusca", SqlDbType.NVarChar);
        SqlParameter num = new SqlParameter("@bo",SqlDbType.Int );
        valor.Value = valorB   ; num.Value = num3 ; 
        cmd.Parameters.Add(valor); cmd.Parameters.Add(num);

        if (conex1.State  == ConnectionState.Closed)
        {  conex1.Open(); }
            cmd.Connection = conex1;
        try
        {
            GridView1.EmptyDataText = "Nao se" + numo.ToString()  +"encontraron registros";
            GridView1.DataSource = cmd.ExecuteReader();
            GridView1.DataBind();
        }
        catch (Exception ex)
        { throw ex; }
        finally
        { conex1.Close(); }

    }

当我传递字符串afonso pena时,该过程返回所有数据就好了,但是当我传入afonso 60时,它返回一个错误,当我传递一个不在数据库中的名称时它再次破裂,就像部分捕获不起作用。

3 个答案:

答案 0 :(得分:1)

当您的问题涉及错误时,最好包含您在问题中看到的错误消息。由于在不知道错误消息的情况下很难调试,请尝试以下方法缩小问题的范围。

尝试重构代码以捕获任何可能的错误,然后再尝试数据绑定GridView

{
    /*
     * put the try at the top of the block to catch exceptions
     * that may occur before you bind the GridView's datasource
     */
    try
    {
        numo = DropDownList1.SelectedValue;
        string valor = "%" + TextBox1.Text.Replace(" ", "%") + "%"; // no reason to NOT one-line this

        /*
         * This would probably be easier to maintain if DropDownList1
         * was bound to an enumeration of these values:
         *     DataTextField="someTextField"
         *     DataValueField="someCorrespondingNumericField"
         * If bound that like above, your switch statement becomes:
         *     Integer.Parse(DropDownList1.SelectedValue, numo);
         * and numo then contains 1, 2, 3, or 4 thus eliminating the need for the variable num3.
         */
        switch (numo)
        { 
            case "Nome":
                num3 = 1;
                break;
            case "Endereço":
                num3 = 2;
                break;
            case "Telefone":
                num3 = 3;
                break;
            case "Pedido":
                num3 = 4;
                break;
        }

        SqlCommand cmd = new SqlCommand();
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.CommandText = "cazacliente2";

        // add parameters and set values all at once
        cmd.Parameters.Add("@vbusca", SqlDbType.NVarChar, 60).Value = valor;
        cmd.Parameters.Add("@bo",SqlDbType.Int).Value = num3;

        if (conex1.State == ConnectionState.Closed)
        {
            conex1.Open();
        }
        cmd.Connection = conex1;

        GridView1.EmptyDataText = "Nao se " + numo.ToString()  +" encontraron registros";
        GridView1.DataSource = cmd.ExecuteReader();
        GridView1.DataBind();
    }
    catch (Exception ex)
    {
        throw ex;
    }
    finally
    {
        conex1.Close();
    }
}

此外,您的存储过程可以更清晰地编写:

ALTER PROCEDURE [dbo].[cazacliente2] (
    @vbusca nvarchar(60)
    , @bo int
) 
AS
    SELECT  idcliente
            , nome
            , endere
            , tel
            , pedido
    FROM    Vw_Conscliente
    WHERE   CASE
                WHEN @bo = 1 THEN nome
                WHEN @bo = 2 THEN endere
                WHEN @bo = 3 THEN tel
                WHEN @bo = 4 THEN pedido
            END LIKE @vbusca

答案 1 :(得分:0)

我会将外卡移到TSQL而不是C#。这样你就可以独立测试它。

您的定义显示最大长度为60.

@vbusca nvarchar(60)

从C#传递给SQL的参数是否大于该值?您应该在Visual Studio中的断点处查看局部变量,以确认这不是真的。

此外,替换参数内的空格意味着参数旁边的逻辑单词只需要按任何顺序匹配。这是你想要的吗?

'afonso 60'匹配'afsonso到商店去牛奶花费60美元'

查看MSDN的外卡使用情况: http://technet.microsoft.com/en-us/library/ms189454.aspx

我在下面使用了动态SQL,因为它减少了整体代码大小。

示例代码更改:

ALTER PROC [dbo].[cazacliente2] (@vbusca nvarchar(32), @bo int) AS

BEGIN

  -- Local variables
  DECLARE @statement VARCHAR(MAX);
  DECLARE @field VARCHAR(MAX);
  DECLARE @expression VARCHAR(MAX);

  -- Make the expression (exact match of @vbusca)
  SET @expression  = '%' + REPLACE(@vbusca,'''', '''''') + '%';

  -- Optional way (match words in @vbusca in order)
  -- SET @expression  = '%' + REPLACE(REPLACE(@vbusca,'''', ''''''), ' ', '%') + '%'

  -- Which field
  SELECT @field =
    CASE @bo 
      WHEN 1 then 'nome'
      WHEN 2 then 'endere'
      WHEN 3 then 'tel'
      WHEN 4 then 'pedido'
      ELSE 'nome'
    END;

  -- Make up the dynamic SQL
  SET @statement = 'select idcliente, nome, endere, tel, pedido ' + 
      ' from Vw_Conscliente where ' + @field + ' like ' + @expression;

  -- Execute the SQL statement
  EXEC @statement;

END;

我将为我将来编写的任何动态TSQL添加警告建议。以下是如何处理注射问题的链接。

http://technet.microsoft.com/en-us/library/ms161953(v=sql.105).aspx

更新SP以通过减少搜索模式大小和处理参数内的单引号来处理问题。

答案 2 :(得分:0)

我认为这是迄今为止最好的解决方案,没有SQL注入,在传递无效的@bo时会处理,默认为nome。

ALTER PROCEDURE [dbo].[cazacliente2] (@vbusca nvarchar(60), @bo int) 
AS
    SELECT  
        idcliente
      , nome
      , endere
      , tel
      , pedido
    FROM    
      Vw_Conscliente
    WHERE   
        CASE
            WHEN @bo = 1 THEN nome
            WHEN @bo = 2 THEN endere
            WHEN @bo = 3 THEN tel
            WHEN @bo = 4 THEN pedido
            ELSE nome    
        END LIKE @vbusca;