I'm totally new to C#. I am validating username and password with case-sensitive
from database sql server 2008. Here is my login code; what should I do?
SqlConnection conn = new SqlConnection(#"Data Source=.\SQLEXPRESS;Initial Catalog=db_WiBo;Integrated Security=True");
SqlCommand cmd = new SqlCommand("SELECT * from tb_Account where Username= '"+textBox1.Text+"' AND Password= '"+textBox2.Text+"' ", conn);
conn.Open();
SqlDataReader reader = cmd.ExecuteReader()
if (reader.HasRows)
{
reader.Close();
this.Hide();
}
Thanks in advance
1) you should be using stored procedures or parameterised query instead of SQL Concatenation. you are presenting a huge SQL Server injection security flaw in your code already.
what is the problem you are having? code looks fine - are you sure the inputs match the data in the database if there are no records being retrieved?
the code simply executes the query and if found, closes the reader and hides the form.
you should also not store raw passwords in the DB - another security flaw. instead, hash them/encrypt them and check that value against the hashed/encrypted value from the input.
for case sensitivity, you could use Collation
http://technet.microsoft.com/en-us/library/ms184391.aspx
http://blog.sqlauthority.com/2007/04/30/case-sensitive-sql-query-search/
A few things:
You are missing a ';' at the end of SqlDataReader reader = cmd.ExecuteReader().
As was already mentioned, use a Stored Procedure for what you are doing.
As was also mentioned, use parameterized queries since you are accepting input from textboxes.
Use a using statement to manage your connection and command objects.
Don't forget to .Close() your connection when you are done.
Oh, and I almost forgot, hash your passwords!
Here is an example of the above:
using (SqlConnection conn = new SqlConnection(#"Data Source=.\SQLEXPRESS;Initial Catalog=db_WiBo;Integrated Security=True"))
{
using (SqlCommand cmd = new SqlCommand(#"SELECT * from tb_Account where Username= '#username' AND Password= '#password' ", conn))
{
cmd.Parameters.Add("#username", textBox1.Text);
cmd.Parameters.Add("#password", textBox2.Text);
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.HasRows)
{
reader.Close();
this.Hide();
}
conn.Close();
}
}
Other than your SQL injection issues, you need to use a collation or cast to binary. I found another SO question that has a bunch of helpful things:
How to do a case sensitive search in WHERE clause (I'm using SQL Server)?
First of all: Do not use string concat for that. This can easily be used for code injection.
You can use stored procedures instead, or LinQ to SQL or even use the built-in membershipprovider
Notwithstanding the design issues already pointed out with respect to security, if your SQL Server instance's default collation is case-insensitive, you'll need to select a suitable collation. The default collation for a SQL Server installation is [usually, depending on the server locale] SQL_Latin1_General_Cp1_CI_AS, meaning Latin-1 code page, case-insensitive, accent-sensitive.
When you create a database, you can specify a default collation for that database. And when you create a table, you may specify the collation to be used for each char, varchar, nchar or nvarchar column.
You may also change these via appropriate DDL statements. Note that altering the collatino may affect data integrity, causing things like primary keys and unique indices to be broken.
Create a table with and specifying the collation for its columns is easy:
create table account
(
id int not null identity(1,1) primary key clustered ,
user_id varchar(32) collate SQL_Latin1_General_Cp1_CS_AS not null unique ,
password varchar(32) collate SQL_Latin1_General_Cp1_CS_AS not null unique ,
...
)
You may use alter table and alter database to change the collations as well.
Supported collations can be found at http://technet.microsoft.com/en-us/library/ms180175.aspx and http://technet.microsoft.com/en-us/library/ms188046.aspx
You should
Note that mixed collations can cause problems when comparing 2 columns, and
Heed the security issues raised by others.
Related
I am creating a voting system. but this thing is not letting me move on to my project.
It says that
"the given key was not present in the dictionary"
here is the code.
error says in login = cmd.ExecuteReader();
MySqlCommand cmd = new MySqlCommand();
cmd.CommandText = "Select * from candidate where StudentNumber = #student";
cmd.Parameters.AddWithValue("#student", stuBox.Text);
cmd.Connection = connection;
MySqlDataReader login;
login = cmd.ExecuteReader();
It's happen when table not exist, column not available.
just verify your table
Or update below
cmd.Parameters.AddWithValue("#student", stuBox.string);
Although the documentation states column names are not case sensitive, I have indeed encountered peculiarities when querying MySQL from C# to do with incorrect table and column name casing.
I cannot explain the reason, but my suspicion it has to do with server and connection collations and the way different client libraries handle it.
I would suggest you double check your table name and column exact spellings and use backticks to quote all identifiers.
I posted about a different issue I had earlier, and with some help resolved that.
I am now receiving a syntax error centered around the following code:
importConnection.Open();
Console.WriteLine("Foxpro connection open");
OleDbCommand deleteOleDbCommand = new OleDbCommand(#"TRUNCATE TABLE CLIENT",
importConnection);
Console.WriteLine("writing to table");
Console.ReadKey();
using (OleDbCommand importCommand = new OleDbCommand(
string.Format("INSERT INTO CLIENT (Title,Fname,Sname)" + "VALUES ({0},{1},{2})",
exportReader.GetValue(0), exportReader.GetValue(1), exportReader.GetValue(2))))
importCommand.ExecuteReader();
With this being the output:
Output Text
using break points I have determined that the export reader calls are receiving data. I've narrowed it down to an issue with:
"VALUES ({0},{1},{2})",
exportReader.GetValue(0), exportReader.GetValue(1), exportReader.GetValue(2))))
I have confirmed that data can be inserted by doing the following:
using (OleDbCommand importCommand =
new OleDbCommand(string.Format(
"INSERT INTO CLIENT (Title,Fname,Sname)" + "VALUES (Mr,Joshua,Cameron-Mackintosh)",
importConnection)))
This causes no problems, so I know the issue does not lie with the underlying connection or command.
Others correctly comment about SQL-Injection, however VFP is less impacted to SQL-Injection, it can be just the same. Main reason, VFP doesn't really work with multiple queries the same way other sql engines allow by a ";" identifying break between statements. However, with mismatched quotes, it CAN and WILL break your sql-statements from actually running.
Having said that, VFP OleDb provider does allow parameterizing, but does so without "named" parameters. It does it with "?" as a place-holder for where the value would be inserted by the .net framework, and you don't have to convert the data type as long as it is in the same expected format (ex: string, numeric, date)
change your OleDbCommand to
"INSERT INTO CLIENT (Title, Fname, Sname ) values ( ?, ?, ? )"
Then, set your parameters via
importCommand.Parameters.Add( "parmForTitle", exportReader.GetValue(0));
importCommand.Parameters.Add( "parmForFName", exportReader.GetValue(1));
importCommand.Parameters.Add( "parmForSName", exportReader.GetValue(2));
Also, the parameters must be added in the exact same sequential order as they appear in the query. So, I prefixed them with "parmFor" to indicate it is the parameter placement for the corresponding field being inserted (or updated, or used in select, insert or delete too). The command objects work the same for all the commands. Even if you write a select statement and have values in a WHERE, JOIN or whatever other position.
THEN, ExecuteNonQuery()
It is saying "foxpro connection string" there. If it is done against
a VFP database, then "Truncate table client" wouldn't work in the
first place. That command does not exist in VFP. Instead you could
try using "Delete From Client" which marks the records for deletion.
Or you can use "zap" command with ExecSript that would correspond to
"truncate table" but then the connection needs to use the table
exclusively.
You should quote the string values. Better yet, for any SQL operation you should use parameters. When you use parameters, you should do that in a correct way for the connection you use. Here you are using an OLEDB connection, then you should use ? as a parameter place holder.
A revised version of your code would then be:
importConnection.Open();
Console.WriteLine("Foxpro connection open");
OleDbCommand deleteOleDbCommand = new OleDbCommand(#"Delete from CLIENT",
importConnection);
Console.WriteLine("writing to table");
Console.ReadKey();
using (OleDbCommand importCommand = new OleDbCommand(
#"INSERT INTO CLIENT (Title,Fname,Sname) VALUES (?,?,?)",
importConnection))
{
importCommand.Parameters.AddWithValue("title","");
importCommand.Parameters.AddWithValue("fname","");
importCommand.Parameters.AddWithValue("sname","");
// maybe in a loop here
importCommand.Parameters["title"].Value = exportReader.GetValue(0);
importCommand.Parameters["fname"].Value = exportReader.GetValue(1);
importCommand.Parameters["sname"].Value = exportReader.GetValue(2);
importCommand.ExecuteNonQuery();
// ...
}
PS: You could directly feed the values on the Parameters.AddWithValue instead of creating a separate .Parameters["..."].Value = ... but then you would only be able to do that for a single insertion (not something related to VFP, it is the case for OleDb or Sql or whatever).
You don't need ExecuteReader for an insert statement. Just use ExecuteNonQuery.
In your case, if your columns are character typed, you need to use single quotes with them for example;
VALUES ('{0}', '{1}', '{2}')
Also use white space (not have to but as a good practice) before VALUES part.
"INSERT INTO CLIENT (Title,Fname,Sname)" + " VALUES (Mr,Joshua,Cameron-Mackintosh)",
// ^^^ here
But more important;
You should always use parameterized queries. Prepared statements automatically handle for escape characters for example and this kind of string concatenations are open for SQL Injection attacks.
You must give space to your concatenated strings.
"INSERT INTO CLIENT (Title,Fname,Sname)" + "[space here]VALUES (Mr,Joshua,Cameron-Mackintosh)"
however, it should look like this:
"INSERT INTO CLIENT (Title,Fname,Sname) VALUES (?,?,?)"
Always make use of parametrized queries. Please refer to:
http://blogs.technet.com/b/neilcar/archive/2008/05/21/sql-injection-mitigation-using-parameterized-queries.aspx
I'm trying to get the following code to work:
String connStr = sqlRoutines.connectionString;
SqlConnection sqlConn = new SqlConnection(connStr);
sqlConn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = sqlConn;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT * FROM TABEL=#tabel";
cmd.Parameters.Add("#tabel", SqlDbType.Text).Value = DataContainer.sqlTabel;
SqlDataReader reader = cmd.ExecuteReader();
Console.WriteLine(reader.FieldCount.ToString());
reader.Close();
sqlConn.Close();
Somehow the value "DataContainer.sqlTabel" is not added to the command. Am I missing something here?
Whenever I use cmd.CommandText = "SELECT * FROM" + DataContainer.sqlTabel; everything is working fine. However I want to avoid this method because of the SQL Injection.
Thanks in advance!
EDIT:
I want to achieve a command that uses a variable (which is changed by the user). So I want to have something like this: SELECT * FROM * a variable defined by the use *;. When I use:
cmd.CommandText = "SELECT * FROM #tablename";
cmd.Parameters.Add("#tablename", SqlDbType.Text).Value = DataContainer.sqlTabel;
It doesn't work as well.
I think you try to parameterize table name which you can't. I don't understand what is TABEL either. FROM (Transact-SQL) doesn't have a syntax like that.
You can only parameterize values. Not table names or column names. Specify the table name as part of the SQL. But when you do that, you need very strong validation on the table name before putting it into the SQL, or have a whitelisted set of valid table names, in order to avoid SQL injection attacks.
If you really want to parameterize it, you can use (but not recommended) Dynamic SQL.
SELECT * FROM #tablename
As we have seen, we can make this procedure work with help of dynamic
SQL, but it should also be clear that we gain none of the advantages
with generating that dynamic SQL in a stored procedure. You could just
as well send the dynamic SQL from the client. So, OK: 1) if the SQL
statement is very complex, you save some network traffic and you do
encapsulation. 2) As we have seen, starting with SQL 2005 there are
methods to deal with permissions. Nevertheless, this is a bad idea.
Also use using statement to dispose your database connections.
using(SqlConnection sqlConn = new SqlConnection(connStr))
using(SqlCommand cmd = sqlConn.CreateCommand())
{
...
...
using(SqlDataReader reader = cmd.ExecuteReader())
{
...
}
}
You can't do this. You can only use dynamic SQL. You need to decide for yourself whether SQL injection is a risk and if so you need to code for this, perhaps checking that the value of table doesn't contain anything other than a valid table name. You can check the table name against the system tables to ensure it is valid.
we can't use parameters for either table name or column name. parameters only limited for values. if you want to use parameter for table name then you've to create a stored procedure and then pass the table name as parameter to store procedure. more information can be found here
Table name as parameter
I have to search a Polish text from SQL database in my windows application. In the SQL Database, the field is in Polish language.
Eg: The DB fields are Id, Name and values are 1 , Ąćłń.
I have a textbox for entering searching text. When I enter the textbox value "Ąćłń", now the result is empty. The select query is working fine with English characters. My question is how can I search a Polish text?
This should not be any different than searching English or any other language text....
connect to your database
fire off a parametrized search query, making sure to use nvarchar as your parameter type
show the results!
So basically, something a bit like:
public List<object> Search(string searchArgument)
{
string searchQry = "SELECT (list of columns) FROM dbo.YourTableName WHERE Name = #SearchArg;";
// Define connection and command to use
using (SqlConnection conn = new SqlConnection("....."))
using (SqlCommand cmdSearch = new SqlCommand(searchQry, conn))
{
// add parameter to search command - make sure to define NVarChar and a valid length!
cmdSearch.Parameters.Add("#SearchArg", SqlDbType.NVarChar, 50);
// set parameter value
cmdSearch.Parameters["#SearchArg"].Value = searchArgument;
// open connection, execute query, handle results
conn.Open();
using (SqlDataReader rdr = cmdSearch.ExecuteReader())
{
// loop over rows returned
while (rdr.Read())
{
// do something with results - create your objects that you want to return...
}
// close reader
rdr.Close();
}
// close connection
conn.Close();
}
}
And using an OR Mapper like Entity Framework would make this even easier still.
Alter fulltext catalog CATALOGNAME
REBUILD WITH ACCENT_SENSITIVITY=OFF;
Or specify an accent-sensitive collation in the query. For example:
select *
from users
where name like 'HELEN%' collate SQL_Latin1_General_CP1_CI_AI
If you don't have fulltext catalog (which you should) you can configure the database so that it is accent-sensitive; change the collation to SQL_Latin1_General_CP1_CI_AI.
Options 1 and 2 are simplest from a database administrator's perspective
Option 3 is simplest from a programmer's perspective
Other collation related tips
Version of SQL Server via Select ##Version
SQL Server collation via SELECT CONVERT (varchar, SERVERPROPERTY('collation'));
Table datatype definition of your Polish text (i.e. Nvarchar or varchar)
The ideal polish Collation is case insensitive SQL_Polish_Cp1250_CI_AS_KI_WI
Patch your SQL Server to the most recent level
Default SQL Server collation is SQL_Latin1_General_CP1_CI_AS
Review this Article
WITH ACCENT_SENSITIVITY = {ON|OFF}
Specifies if the catalog to be altered is accent-sensitive or accent-insensitive for full-text indexing and querying.
Notice here:
select * from member where name like 'müller' COLLATE German_PhoneBook_CI_AI
it will find "müller", "mueller", and "Müller"
and
SELECT * FROM mytest WHERE SOUNDEX (col1 )=SOUNDEX ('Muller')
it will find "müller", "mueller", and "Müller"
As a reaction to MySqlParameter as TableName, it seems that MySQL's Connector/NET library doesn't support table names from user input in the following way:
MySqlCommand cmd = new MySqlCommand("SELECT * FROM #table");
cmd.Parameters.AddWithValue("#table",TableNameFromUserInput);
So I tried to find another way, but I couldn't find any libraries that did this for me.
When searching for how to do this manually, I couldn't found anything that didn't tell you to use "prepared statements" from some already defined library, no matter the language.
To my limited knowledge of SQL, I only think it's necessary to put backticks (`) around the user input and then check the input for backticks - but I wanted to be sure.
Question
How do you protect a user specified table name from SQL-Injection when the MySQL Connector doesn't support it?
Check if
TableNameFromUserInput
is an existing table, before executing the query.
That prevents other errors like "table doesnt exist" aswell.
you cannot add tableName (as well as columnName) as parameter in prepared statements because it only supports for a value. For your safety, add additional code to validate tableName, ex.
string tableName = "hello";
tableName = UDFunctionClean(tableName);
string query = String.Format("SELECT * FROM `{0}`", tableName);
MySqlCommand cmd = new MySqlCommand(query);