Can a C# SQL Parameter Contain '=' - c#

So I am trying to create parameters to pass to my query and was wondering if I could pass a parameter that contains an '=' sign in it that replaces the traditional '=' sign in the SQL statement. It would be like the following:
string aoi = "=" + comboBox1.Text;
string comp = "=" + comboBox2.Text;
//Default values of their respective Combo Boxes.
if(aoi == "Area Of Interest")
aoi = "!= NULL";
if (comp == "Company")
comp = "!= NULL";
cmd.CommandText = "SELECT * FROM JobListInfo" +
"WHERE AreaOfInterest #AOI AND Company #Company";
cmd.Parameters.AddWithValue("#AOI", aoi);
cmd.Parameters.AddWithValue("#Company", comp);
The reason I am asking is because if the user doesn't change the default value, I want it to pull all the records (with respect to the rest of the SQL statement). I understand I could create an OR statement, but I have three other parameters I would like to pass as well and didn't want to create 15 OR cases.
EDIT: I found a solution to my problem. I changed the '=' to Like and changed the strings to '%' if they didn't select a value. This shouldn't cause any SQL injection issues, right?
Sample Code:
if(aoi == "Area of Interest")
aoi = "%"
cmd.CommandText = "SELECT * FROM JobListInfo " +
"WHERE AreaOfInterest LIKE #AOI";
cmd.Parameters.AddWithValue("#AOI", aoi);

Not via a parameter. If this were allowed, it would potentially introduce SQL injection vulnerabilities.
A potential solution would be to dynamically create the CommandText string by appending database column names and parameter placeholders to the query's WHERE clause.
WARNING: Do not append input values to the WHERE clause of your query string! This will leave you vulnerable to SQL injection. Instead, append parameter placeholders and then populate them using the cmd.Parameters.AddWithValue() method.
That being said, something like the code below might work. However, it would depend on you selecting a single default value for your combo-boxes. Consequently, you would need to use UI labels instead of default values to describe the combo-boxes in your app.
string MY_DEFAULT_VALUE = 'Pick One:';
string queryString = "SELECT * FROM my_table";
//Populate Dictionary:
Dictionary<string,ComboBox > columnDictionary= new Dictionary<string, ComboBox>();
columnDictionary.Add("COL_A", comboBox1);
columnDictionary.Add("COL_B", comboBox2);
columnDictionary.Add("COL_C", comboBox3);
//etc...
List<KeyValuePair<string, ComboBox>> appendedColumns = new List<KeyValuePair<string, ComboBox>>();
foreach (KeyValuePair<string, ComboBox> entry in columnDictionary)
{
if (!String.Equals(entry.Value.Text, MY_DEFAULT_VALUE, StringComparison.OrdinalIgnoreCase))
{
string currentColumnName = entry.Key;
string currentColumnParameter = "#" + entry.Key;
if (appendedColumns.Count>1)
{
queryString += " AND ";
}
else
{
queryString += " WHERE ";
}
queryString += currentColumnName + " = " + currentColumnParameter;
appendedColumns.Add(entry);
}
}
cmd.CommandText = queryString;
if (appendedColumns.Count > 0)
{
foreach (KeyValuePair<string, ComboBox> entry in appendedColumns)
{
string currentColumnParameter = "#" + entry.Key;
string currentParameterValue = entry.Value.Text;
cmd.Parameters.AddWithValue(currentColumnParameter, currentParameterValue);
}
}
//Continue on your way...

Short answer to your question is, you cannot use '=' as you have shown. So change your code like this;
string aoi = comboBox1.Text;
string comp = comboBox2.Text;
string sql;
if (aoi == "Area Of Interest" && comp == "Company")
{
sql = #"SELECT * FROM JobListInfo WHERE AreaOfInterest Is Not NULL AND Company Is Not NULL";
}
else if(....)
{
sql =............................
}
else
{
sql = #"SELECT * FROM JobListIn WHERE AreaOfInterest = #AOI AND Company = #Company";
}
cmd.CommandText = sql;
cmd.Parameters.AddWithValue("#AOI", aoi);
cmd.Parameters.AddWithValue("#Company", comp);

Related

Using Parameter in Sql Query [duplicate]

I got a runtime error saying "Must declare the table variable "#parmTableName". Meaning having table name as sql parameter in the sql-statement is not allowed.
Is there a better option or suggestion than allowing sql injection attack? I don't want to do this C# script for sql statement " DELETE FROM " + tableName + " ";
using(var dbCommand = dbConnection.CreateCommand())
{
sqlAsk = "";
sqlAsk += " DELETE FROM #parmTableName ";
sqlAsk += " WHERE ImportedFlag = 'F' ";
dbCommand.Parameters.Clear();
dbCommand.Parameters.AddWithValue("#parmTableName", tableName);
dbConnection.Open();
rowAffected = dbCommand.ExecuteNonQuery();
}
Go for a white list. There can only be a fixed set of possible correct values for the table name anyway - at least, so I'd hope.
If you don't have a white list of table names, you could start with a whitelist of characters - if you restrict it to A-Z, a-z and 0-9 (no punctuation at all) then that should remove a lot of the concern. (Of course that means you don't support tables with odd names... we don't really know your requirements here.)
But no, you can't use parameters for either table or column names - only values. That's typically the case in databases; I don't remember seeing one which did support parameters for that. (I dare say there are some, of course...)
As others have already pointed out that you can't use Table Name and Fields in Sql Parameter, one thing that you can try is to escape table name using SqlCommandBuilder, like:
string tableName = "YourTableName";
var builder = new SqlCommandBuilder();
string escapedTableName = builder.QuoteIdentifier(tableName);
using (var dbCommand = dbConnection.CreateCommand())
{
sqlAsk = "";
sqlAsk += " DELETE FROM " + escapedTableName; //concatenate here
sqlAsk += " WHERE ImportedFlag = 'F' ";
dbCommand.Parameters.Clear();
dbConnection.Open();
rowAffected = dbCommand.ExecuteNonQuery();
}
(sqlAsk is string, right?) if it's right so let's try this:
using(var dbCommand = dbConnection.CreateCommand())
{
sqlAsk = "";
sqlAsk += " DELETE FROM <table_name> ";
sqlAsk += " WHERE ImportedFlag = 'F' ";
string table_name = "Your table name here"; //<- fill this as u need
sqlAsk = sqlAsk.Replace("<table_name>", table_name); // it will replace <table_name> text to string table_name
dbConnection.Open();
rowAffected = dbCommand.ExecuteNonQuery();
}

How to get a key from a specific database row when I double click an item on a list?

Basically I have this list of students (alunos) and I want to double click in one of the students and I want it to show a MessageBox containing:
Student No.: {student no. from the selected student here}
Name: {student name from the selected student here}
etc...
Here's the code I have:
void lstAlunos_MouseDoubleClick(object sender, MouseEventArgs e)
{
string query = "SELECT * FROM (" +
"SELECT" +
"ROW_NUMBER() AS rownumber," +
"columns" +
"FROM Alunos" +
") AS foo" +
"WHERE rownumber = " + lstAlunos.SelectedIndex;
using (connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(query, connection))
using (var reader = command.ExecuteReader())
{
connection.Open();
reader.Read();
string numAluno = reader.GetString(0);
string nomeAluno = reader.GetString(1);
string apelidoAluno = reader.GetString(2);
string contactoAluno = reader.GetString(3);
string emailAluno = reader.GetString(4);
}
int index = this.lstAlunos.IndexFromPoint(e.Location);
if (index != System.Windows.Forms.ListBox.NoMatches)
{
MessageBox.Show("Nome: " + nomeAluno);
}
}
Add spaces to the ends of the strings you're concatenating. Right now this segment:
"columns" +
"FROM" +
will give you "columnsFROM" which is obviously bad SQL.
Some other suggestions:
Add error handling. The exception you got from this should give you a clue as to where the problem is.
Use parameters instead of concatenating string values. It will protect you from SQL Injection attacks and take care of formatting for you.
Don't use ROW_NUMBER() without some sore of explicit order. THere's no guarantee that you'll get the rows in the same order that they were saved in previously. Use an ID column instead.

C# replace parameters in query with defined values [duplicate]

This question already has answers here:
parameterized queries vs. SQL injection
(4 answers)
Closed 6 years ago.
string[] theParms = ['parm1', 'parm2'];
string theQuery = "SELECT something, somethingAgain " +
"FROM aDBTable " +
"WHERE something = '{?}'" +
"AND something <> '{?}'";
I am needing to replace the {?}'s with the defined parms in theParms.
Is there some type of loop in C# that I can use in order to loop through the string and replace each found {?} with the corresponding parm value?
Something like this:
First loop:
SELECT something, somethingAgain
FROM aDBTable
WHERE something = 'parm1' AND something <> '{?}'
Second loop:
SELECT something, somethingAgain
FROM aDBTable
WHERE something = 'parm1' AND something <> 'parm2'
Is there some type of REGEX or common framework function that can do the above?
sql injection check
bool injectionCheckin = new injectionCheck().inCheck(theFinalQuery);
public class injectionCheck
{
public bool inCheck(string queryString)
{
var badWords = new[] {
"EXEC", "EXECUTE", ";", "-", "*", "--", "#",
"UNION", "DROP","DELETE", "UPDATE", "INSERT",
"MASTER", "TABLE", "XP_CMDSHELL", "CREATE",
"XP_FIXEDDRIVES", "SYSCOLUMNS", "SYSOBJECTS",
"BC_HOME_ADDRESS1", "BC_HOME_ADDRESS2", "BC_HOME_CITY", "BC_HOME_COUNTY", "BC_HOME_POSTAL", "BC_MAIL_ADDRESS1",
"BC_MAIL_ADDRESS2", "BC_MAIL_CITY", "BC_MAIL_COUNTY", "BC_MAIL_POSTAL", "BC_MAIL_STATE", "FLSA_STATUS", "GRADE",
"GRADE_ENTRY_DT", "HIGHEST_EDUC_LVL", "LAST_INCREASE_DT", "BC_SALP_DESCR", "BC_SALP_DESCRSHORT", "SAL_ADMIN_PLAN"
};
string pattern = "(?<!\\w)(" + Regex.Escape(badWords[0]);
foreach (var key in badWords.Skip(1))
{
pattern += "|" + Regex.Escape(key);
}
pattern += ")(?!\\w)";
dynamic _tmpCount = Regex.Matches(queryString, pattern, RegexOptions.IgnoreCase).Count;
if (_tmpCount >= 1)
return true;
else
return false;
}
}
Always create Sql-commands by parameterized queries:
using (SqlConnection conn = new SqlConnection(DatabaseConnectionString))
using (SqlCommand cmd = conn.CreateCommand())
{
var #params = new Dictionary<string, object>{
{ "something", myValue },
{ "somethingDifferent", anotherValue },
};
cmd.CommandText = "SELECT something, somethingAgain " +
"FROM aDBTable " +
"WHERE something = #something'" +
"AND something <> #somethingDifferent'";
foreach (KeyValuePair<string, object> item in values)
{
cmd.Parameters.AddWithValue("#" + item.Key, item.Value);
}
DataTable table = new DataTable();
using (var reader = cmd.ExecuteReader())
{
table.Load(reader);
return table;
}
}
}
This prevents all sort of SqlInjection and you won´t any weird checks as yours with the badlist which is quite messy and does not really prevent you, you can easily bypass the list with some escaping for instance. In particular: why do you want to write your own validation when there allready are ready-to-use methods that do exactly what you want?
Why not just use String.Format?
string[] theParms = new string[] { "parm1", "parm2" };
string theQuery = #"SELECT something, somethingAgain
FROM aDBTable
WHERE something = '{0}'
AND something <> '{1}'";
var res = string.Format(theQuery, theParms);
Result:
SELECT something, somethingAgain
FROM aDBTable
WHERE something = 'parm1'
AND something <> 'parm2'
If you want to do it in either case, you could do it without a loopy as follows.
string theQuery = String.Format( "SELECT something, somethingAgain " +
"FROM aDBTable " +
"WHERE something = '{0}'" +
"AND something <> '{1}'",
theParams[0], theParams[1] );
Okay, to avoid Injection and all that, why don't you do it like this:
string[] theParms = // initialization
string theQuery = // initialization
SqlCommand cmd = new SqlCommand(/* enter connection string */, theQuery)
for(int i = 0; i < theParams.Length; i++)
{
int index = cmd.Text.IndexOf("{?}");
if(index > -1)
{
string pName = string.Format("#p{0}", i);
cmd.Text = cmd.Text.Remove(index, 3).Insert(index, pName);
cmd.Parameters.Add(new SqlParameter() { Name = pName, Value = theParms[i] });
}
}
That should avoid any manual injection checks alltogether... at least if you can't get the query pre-compiled and have to load it at runtime. Otherwise just formulate the SqlCommand's text appropriately and you'll not need a loop or anything. Just a simple initialization:
SqlCommand cmd = new SqlCommand(/* enter connection string */, "SELECT something, somethingAgain FROM aDBTable WHERE something = #p0 AND something <> #p1");
cmd.Parameters.Add(new SqlParameter() { Name = "#p0", Value = theParms[0] });
cmd.Parameters.Add(new SqlParameter() { Name = "#p1", Value = theParms[1] });
You can use IndexOf and substrings to find each instance
for(int i = 0; i < theParms.GetLength(0); i++)
{
string[] tempStrings = new string[]{ theQuery.Substring(0,theQuery.IndexOf("{?}") - 1),
theQuery.Substring(theQuery.IndexOf("{?}"), 3),
theQuery.Substring(theQuery.IndexOf("{?}") + 4) }
tempStrings[1] = tempStrings[1].Replace("{?}", theParms[i]);
theQuery = String.Join("", tempStrings);
}
Though seeing as you check for injection afterwards it is definitely much better to use String.Format
You don't have to handle it by yourself. Instead, ADO.NET allows you define parameters and set their values. See the sample here .MSDN

How to use Linq instead of SQL Injection query for custom search

I would like to use Linq instead of below hardcoded Sql Injection to search from SqlServer DATABASE TABLES. How to retrieve Dynamically generated web controls input texts in C# Linq and replace the entire Sql injection in Linq for searching.
My C# code:
protected void Search_Button_Click(object sender, EventArgs e)
{
try
{
Table maintable = Select.FindControl("dynamic_filter_table_id") as Table;
int rc = maintable.Rows.Count;
if (rc == 1)
{
DropDownList D1 = maintable.FindControl("MainDDL") as DropDownList;
if (D1.SelectedValue.Contains("decimal"))
{
TextBox T1 = maintable.FindControl("txtbox1") as TextBox;
TextBox T2 = maintable.FindControl("txtbox2") as TextBox;
SqlDataAdapter sql = new SqlDataAdapter("SELECT F.Col1,F.Col2,V.COL1, col2,col3, col4 , col5, cl6 FROM TABLE1 as V , TABL2 as F WHERE V.Col1 = F.Col1 AND " + DDL1.SelectedItem.Text + " >= " + T1.Text + " AND " + DDl1.SelectedItem.Text + " <= " + T2.Text, con);
DataSet data = new DataSet();
sql.Fill(data);
con.Close();
Session["DataforSearch_DDL"] = data.Tables[0];
}
}
}
catch
{
ImproperSearch();
}
}
Why don't you just rewrite your query to be SQL-injection safe? LINQ won't give you any benefit.
You can achieve that by doing two things.
The first is to secure the column names. That is accomplished by specifying which characters is allowed for column names (more secure than trying to figure out what characters is not allowed). In this case I remove everything but letters and digits. If you have column names which contains underscore, just add that to the check.
The next thing is to use parameterized queries. Each ADO.NET driver has built in support for that, so you just have to specify the value using cmd.Parameters.AddWithValue. By doing so the value isn't part of the query string and hence there is no potential SQL injection.
using (var con = yourConnectionFactory.Create())
{
using (var cmd = new SqlCommand(con))
{
var safeKey1 = OnlyLettersAndDigits(DDL1.SelectedItem.Text);
var safeKey2 = OnlyLettersAndDigits(DDL2.SelectedItem.Text);
cmd.CommandText = "SELECT F.Col1,F.Col2,V.COL1, col2,col3, col4 , col5, cl6 " +
" FROM TABLE1 as V , TABL2 as F WHERE V.Col1 = F.Col1 " +
" AND " + safeKey1 + " >= #text1 " +
" AND " + safeKey2 + " <= #text2 ";
cmd.Parameters.AddWithValue("text1", T1.Text);
cmd.Parameters.AddWithValue("text2", T2.Text);
var adapter = new SqlDataAdapter(cmd);
var data = new DataSet();
sql.Fill(data);
Session["DataforSearch_DDL"] = data.Tables[0];
}
}
public string OnlyLettersAndDigits(string value)
{
var stripped = "";
foreach (var ch in value)
{
if (char.IsLetterOrDigit(ch))
stripped += ch;
}
return stripped;
}
You can use store procedure for customer search, It will work for both ADO.Net and LINQ approach. Just create a SP and add it to your DBML file very simple.
Here is the link how you can use SP in LINQ
http://www.mssqltips.com/sqlservertip/1542/using-stored-procedures-with-linq-to-sql/

C# SQL Multiple IN Selectors

My output query looks like:
select * from Calls where CallerID = "User.Name" and Endpoint in ("C,D,V") order by JoinTime desc;
My C# query string with parameters looks like this:
string SQLQuery = "select * from Calls where CallerID = #UserName and EndpointType in ({0}) order by JoinTime desc";
The code to add the parameters looks like this:
...
string[] Endpoints = new string[] {"C","D","V"}; //EXAMPLE string array
string UserNameStr = "User.Name"; //EXAMPLE string UserNameStr value
...
string[] paramNames = Endpoints.Select((s, i) => "#endpoint" + i.ToString()).ToArray();
string inClause = string.Join(",", paramNames);
using (cmd = new MySqlCommand((string.Format(SQL, inClause)),connection))
{
for (int i = 0; i < paramNames.Length; i++)
{
cmd.Parameters.AddWithValue(paramNames[i], Endpoints[i]);
}
}
cmd.Parameters.Add("#UserName", MySqlDbType.String).Value = UserNameStr;
MySqlDataReader dataReader = cmd.ExecuteReader();
...
But what if I wanted to add another IN operator so the output query would look like this ;
select * from Calls where CallerID = "User.Name" and Endpoint in ("C","D","V") and ConferenceCall in ("D","C") order by JoinTime desc;
How do I do that? Is there some features in Linq that could be used?
Same way you do it the first time:
// endpoints = comma-delimited list of endpoints
// conferenceCalls = comma-delimited list of conference calls
string SQLQuery = "select * from Calls " +
"where CallerID = #UserName and " +
"EndpointType in ({0}) and " +
"ConferenceCall in ({1}) " +
"order by JoinTime desc";
cmd = new MySqlCommand((string.Format(SQL, endpoints, conferenceCalls)),connection);
As noted in comments, be VERY careful that you validate the strings to avoid SQL injection attacks. There's not a direct way to pass a collection as a SQL parameter. There are ways to do it (passing a delimited string and parsing it is the most common I've seen), but if you are in control of setting the value and validate the data then you should be fine.

Categories

Resources