skip to Main Content

I have an ASP.net C# site. I feed one of the ListView in that with this code and it’s work:

protected void BindData()
{
    string forwardedSearchText = Request.QueryString["SearchText"];
    string forwardedSearchColumn = Convert.ToString(Session["SearchTitle"]);

    string strsql = "Select TbSoore.IdSoore, TbSoore.NameSoore, TbAye.NumberAye, TbAye.IdAye, TbAye.TextAye, TbAye.TextTarjome From TbAye INNER JOIN TbSoore ON TbAye.IdSoore = TbSoore.IdSoore Where FreeText((" + forwardedSearchColumn + "),N' " + forwardedSearchText + "')";

    DataTable dt = new DataTable();
    using (SqlConnection con = new SqlConnection(strcon))
    {
        using
            (SqlCommand cmdSQL = new SqlCommand(strsql, con))
        {
            con.Open();
            ListViewSearchResults.DataSource = cmdSQL.ExecuteReader();
            ListViewSearchResults.DataBind();
        }
    }

}

Now I want to change the query string style for better security to:

$@"Select TbSoore.IdSoore, TbSoore.NameSoore, TbAye.NumberAye, TbAye.IdAye, TbAye.TextAye, TbAye.TextTarjome From TbAye INNER JOIN TbSoore ON TbAye.IdSoore = TbSoore.IdSoore Where FreeText(({forwardedSearchColumn}),N' @forwardedSearchText ')";

So change BindData() to:

protected void BindData()
{
    string forwardedSearchText = Request.QueryString["SearchText"];
    string forwardedSearchColumn = Convert.ToString(Session["SearchTitle"]);

    string strsql = $@"Select TbSoore.IdSoore, TbSoore.NameSoore, TbAye.NumberAye, TbAye.IdAye, TbAye.TextAye, TbAye.TextTarjome From TbAye INNER JOIN TbSoore ON TbAye.IdSoore = TbSoore.IdSoore Where FreeText(({forwardedSearchColumn}),N' @forwardedSearchText ')";

    DataTable dt = new DataTable();
    using (SqlConnection con = new SqlConnection(strcon))
    {
        using
            (SqlCommand cmdSQL = new SqlCommand(strsql, con))
        {
            cmdSQL.Parameters.Add("@forwardedSearchText", SqlDbType.NVarChar).Value = forwardedSearchText;
            con.Open();
            ListViewSearchResults.DataSource = cmdSQL.ExecuteReader();
            ListViewSearchResults.DataBind();
        }
    }

}

But it doesn’t work. I don’t get any error but the table is empty.

Can any one help me?

2

Answers


  1. Chosen as BEST ANSWER

    I found the problem. Because I want to search with Persian Language in SQL, I have to use N before text that want to search. in FreeText(({forwardedSearchColumn}),N' @forwardedSearchText ')" , I should transfer the N' and ' in to @forwardedSearchText parameter, instead of in sql query string.

    That means DataBind() should be like this:

            protected void BindData()
        {
            string forwardedSearchText = "N'"+Request.QueryString["SearchText"]+"'"; //I change this line
            string forwardedSearchColumn = Convert.ToString(Session["SearchTitle"]);
            bool SearchAye = Convert.ToBoolean(Session["SearchAye"]);
    
            string strsql = $@"Select TbSoore.IdSoore, TbSoore.NameSoore, TbAye.NumberAye, TbAye.IdAye, TbAye.TextAye, TbAye.TextTarjome
            From TbAye INNER JOIN TbSoore ON TbAye.IdSoore = TbSoore.IdSoore 
            Where Contains(({forwardedSearchColumn}), @forwardedSearchText )"; // and change this line
    
    
        DataTable dt = new DataTable();
            using (SqlConnection con = new SqlConnection(strcon))
            {
                using
                    (SqlCommand cmdSQL = new SqlCommand(strsql, con))
                {
                    cmdSQL.Parameters.Add(new SqlParameter("@forwardedSearchText", forwardedSearchText));
                    con.Open();
                    dt.Load(cmdSQL.ExecuteReader());
                }
                ListViewSearchResultAye.DataSource = dt;
                ListViewSearchResultAye.DataBind();
            }
    

  2. A good example as to how formatting the SQL text in code, and not having it warp off the page ensures that when reading the code, you can with ease see all of the text.

    I would consider a view, or even better a stored procedure, and that would have eliminated this error due to difficult to read in-line SQL.

    SQL parameters don’t use nor require quotes.

    I suggest this:

        protected void BindData()
        {
            string forwardedSearchText = Request.QueryString["SearchText"];
            string forwardedSearchColumn = Convert.ToString(Session["SearchTitle"]);
    
            string strsql = 
                $@"Select TbSoore.IdSoore, TbSoore.NameSoore, TbAye.NumberAye, TbAye.IdAye, TbAye.TextAye,
                TbAye.TextTarjome From TbAye
                INNER JOIN TbSoore ON TbAye.IdSoore = TbSoore.IdSoore
                Where FreeText({forwardedSearchColumn},@forwardedSearchText)";
    
            DataTable dt = new DataTable();
            using (SqlConnection con = new SqlConnection(strcon))
            {
                using
                    (SqlCommand cmdSQL = new SqlCommand(strsql, con))
                {
                    cmdSQL.Parameters.Add("@forwardedSearchText", SqlDbType.NVarChar).Value = forwardedSearchText;
                    con.Open();
                    ListViewSearchResults.DataSource = cmdSQL.ExecuteReader();
                    ListViewSearchResults.DataBind();
                }
            }
    
        }
    

    Also, if the ListView is going to require use of the full row during databinding such as often used for formatting of each row, then feeding the ListView with a reader does not allow use of the full data row during the binding process.

    So, I thus suggest this:

       cmdSQL.Parameters.Add("@forwardedSearchText", SqlDbType.NVarChar).Value = forwardedSearchText;
       con.Open();
       DataTable dt = new DataTable();
       dt.Load(cmdSQL.ExecuteReader());
    
       ListViewSearchResults.DataSource = dt;
       ListViewSearchResults.DataBind();
    

    With above, we have reduced string concatenation for the search terms, but we still have an injection vulnerability.

    The problem of course is that the SearchColumn is still a concatenation expression, but worse is T-SQL does not allow column names as a parameter.

    If the column is to only ever be one column, then I suggest hard coding of that column, or even introduction of a switch case statement for the given column name.

    If the number of columns is variable (and can be more then one column), then at least ensure that this selecting is some kind of ListBox, or other type of UI in which the user does not type in the column names.

    As noted, concatenation of those column names still represents a security risk.

    So, I would ensure that the column selecting of your UI does not allow free form (text box input) for the column names.

    I should also point out in your posted code, you defined a DataTable, but it is not used. And reading above, I in fact missed that you already declared the DataTable.

    Hence, we now have this code:

        protected void BindData()
        {
            string forwardedSearchText = Request.QueryString["SearchText"];
            string forwardedSearchColumn = Convert.ToString(Session["SearchTitle"]);
    
            string strsql = 
                $@"Select TbSoore.IdSoore, TbSoore.NameSoore, TbAye.NumberAye, TbAye.IdAye, TbAye.TextAye,
                TbAye.TextTarjome From TbAye
                INNER JOIN TbSoore ON TbAye.IdSoore = TbSoore.IdSoore
                Where FreeText({forwardedSearchColumn},@forwardedSearchText)";
    
            DataTable dt = new DataTable();
            using (SqlConnection con = new SqlConnection(strcon))
            {
                using (SqlCommand cmdSQL = new SqlCommand(strsql, con))
                {
                    cmdSQL.Parameters.Add("@forwardedSearchText", SqlDbType.NVarChar).Value = forwardedSearchText;
                    con.Open();
                    dt.Load(cmdSQL.ExecuteReader());
                }
            }
            ListViewSearchResults.DataSource = dt;
            ListViewSearchResults.DataBind();
        }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search