I am making a Login Page. For that i am going to do authenticate the username and password from database. As i execute the program query will run and it return a -1 value. As the username and password is correct. Please Help me out. My program code is as Follow:
public partial class Home : System.Web.UI.Page
{
SqlConnection objcon;
String query;
SqlCommand cmd;
int num;
//SqlDataAdapter DataAdapter;
protected void Page_Load(object sender, EventArgs e)//db open in page load.
{
objcon = new SqlConnection("Data Source String");
objcon.Open();
}
//query execution and authentication on button click
protected void Button1_Click(object sender, EventArgs e)
{
query = "select * from tbl_user where UserName='" + txtUname.Text + "' and Password='" + txtPwd.Text + "'";
cmd = new SqlCommand(query,objcon);
num = cmd.ExecuteNonQuery();
//Label3.Text = num.ToString();
if (num == -1)
Label3.Text = "Correct";
else
Label3.Text = "Incorrect";
objcon.Close();
}
}
Look at this code:
num = cmd.ExecuteNonQuery();
Now given that you're creating a command based on a variable called query, do you really think calling a method with the phrase non-query in it makes sense? From the docs for ExecuteNonQuery, if you're not convinced yet:
For UPDATE, INSERT, and DELETE statements, the return value is the number of rows affected by the command. [...] For all other types of statements, the return value is -1.
Your statement is a SELECT query, so it's returning -1 exactly as documented.
I suspect you should be using ExecuteScalar or ExecuteReader. For example, if you're trying to get the number of matches, you should use:
SELECT COUNT(*) ... (rest of query, parameterized of course)
Personally I prefer that over taking -1 or null as per James's answer, but it's a matter of taste.
If you're not trying to get the count of matches, it's not clear why you're assigning to an int variable in the first place.
EDIT: Additional issues: (As already mentioned in comments)
Only create and open the SqlConnection when you need to, not in the constructor
Use using directives for both the SqlConnection and SqlCommand to they're closed even when there's an exception
Don't include user input directly in SQL - use parameterized SQL instead, to SQL avoid injection attacks, improve code/data separation, and avoid conversion errors
Don't store your users' password directly in the database in plaintext - that's a really horrible thing for any web site to do.
Don't try to write your own user authentication code in the first place - it's been done for you already, in many different places
What you want is to execute a scalar query, meaning that it returns a single value. In the case of your query, if the username and password match, simply select -1:
SELECT -1 FROM tblUser WHERE Username = 'James' AND Password = 'Johnson'
If a value is returned, that value will be -1 and you know you have a match. If no value (null) is returned it didn't match.
EDIT
Aside from just answering your question, there are some major problems with your code that you need to address:
You're opening a new connection each time the page loads. That's a big no-no! Not only are you opening a new connection on each page load, but you're also not closing the connection once the query has executed.
Instead of using concatenation to build your query, use a parameterized query to avoid the risk of SQL injection. Someone with even a little knowledge of SQL could easily escape your query and wreak havoc on your data.
Related
I'm trying to update a Database table and getting the error
"MySql.Data.MySqlClient.MySqlException: 'You have an error in your SQL
syntax; check the manual that corresponds to your MySQL server version
for the right syntax to use near 'group='superadmin' WHERE
identifier='steam:steam:1100001098b5888'' at line 1'"
// Creates query to run
public void UpdateInfo(String jobTitle, int jobGrade, String adminLevel, String identifier) {
// Opens the database connection if it's not already open
if (!(databaseConnected)) {
openConnection();
}
// Creates query to run
String query = "UPDATE " + table + " SET job=#jobTitle, job_grade=#jobGrade, group=#adminLevel WHERE identifier=#identifier";
// Makes a new command
MySqlCommand cmd = new MySqlCommand(query, connection);
// Replaces the # placeholders with actual variables
cmd.Parameters.AddWithValue("#jobTitle", jobTitle);
cmd.Parameters.AddWithValue("#jobGrade", jobGrade);
cmd.Parameters.AddWithValue("#adminLevel", adminLevel);
cmd.Parameters.AddWithValue("#identifier", identifier);
// Executes it and if it's...
if (cmd.ExecuteNonQuery() > 0) {
// Successful
MessageBox.Show("Successfully updated information");
closeConnection();
return;
} else {
// Not successful
MessageBox.Show("Error with updating information!");
// Closes the connection again to prevent leaks
closeConnection();
return;
}
}
I tried your query on https://sqltest.net/ and noticed it highlighted "group" when I tried to create the table. I'm wondering if the problem might be the usage of "group" as a column name since it's a reserved word.
Is it possible to try renaming the column to group_level or adding back ticks around 'group' or "group" and seeing if that works?
So for example
'group'=#grouplevel
I found this thread and this thread on renaming the column where they had issues with "group" as a column name. Adding backticks seemed to solve both problems.
EDIT: As per OP, double quotes (") solved the issue instead of single. Edited answer to include.
Try change query like this
String query = "UPDATE " + table + " SET job='#jobTitle', job_grade=#jobGrade, group='#adminLevel' WHERE identifier='#identifier'";
if you input String value with query, you need to use 'this' for work
I hope this will work for you.
if not, you can use String.Format for that like this.
String Query = String.Format("Update `{0}` Set job='{1}', job_grade={2}, group='{3}' Where identifier='{4}'", table, jobTitle, jobGrade, adminLevel, identifier);
I am working on a project where the client has reported an SQL injection flaw in the code. Here is my code…
1 public int ExecuteNonQuery(string query, SqlParameter[] parameters)
2 {
3 using (SqlCommand command = CreateCommand(query, parameters))
4 {
5 int rowsAffected = command.ExecuteNonQuery();
6 return rowsAffected;
7 }
8 }
And the CreateCommand method goes as
private SqlCommand CreateCommand(string commandText, SqlParameter[] parameters)
{
SqlCommand retVal = this.connection.CreateCommand();
retVal.CommandText = commandText;
retVal.CommandTimeout = this.commandsTimeout;
retVal.Parameters.AddRange(parameters);
return retVal;
}
The flaw is reported at line number 3. I am unable to understand what kind of attack an happen here as this is a console application. But I have to fix the flaw and I don't know how to fix it.
Query is
#"delete from {0} where runId in
( select runId from {0}
inner join
( select sId as sId_last,
wfId as wfId_last,
max(runId) as runId_last from {0} where endTime is NULL
group by sId, wfId ) t1
on endTime is NULL and sId = sId_last and wfId = wfId_last
and (runId <> runId_last or startTime < #aDateTime)
)";
Help appreciated.
Thanks.
that code is injection-free... But note that the methods that call ExecuteNonQuery could build the query by composing strings.
An injection attack happens when you do something like:
string name = ...; // A name selected by the user.
string query = "SELECT * FROM MyTable WHERE Name = '" + name + "'";
so when you compose a query using pieces of text that are of external origin.
Note that a more subtle injection attack could be multi-level:
string name = // The result of a query to the db that retrieves some data
// sadly this data has been manipulated by the attacker
string query = "SELECT * FROM MyTable WHERE Name = '" + name + "'";
In general you don't need a user interface to cause an injection attack...
You could query something from a web site/from the db, and use the unsanitized result to query the db (as in the last example), causing an injection attack... Or even using the content of the configuration file could cause an injection attack: the priviledges needed to modify the configuration file could be different than the ones needed to do something on the DB, and a malicious user could have the priviledges to modify the configuration file but not have direct access to the DB. So he could use the program as a trojan horse against the DB.
about the query
The weak point of that query (that is a composition of strings) is in how the {0} is calculated. Is it a string chosen in a group of fixed strings? Something like:
string tableName;
if (foo)
tableName = "Foo";
else if (bar)
tableName = "Bar";
or is it something more user controlled?
If the table names are fixed in code, then there shouldn't be any injection attack possible. If the table names are "extracted" from some user input/some other table the user could have access, we return to the problem I showed before.
You've exposed a public method which can be accessed by any code that allows any SQL expression to be executed.
I would look at changing that method to being internal or private instead so that not just any code can call that method.
Line 3:
using (SqlCommand command = CreateCommand(query, parameters))
Both Query and parameters are available in this line.
SQL injection should not be prevented by trying to validate your input; instead, that input should be properly escaped before being passed to the database.
How to escape input totally depends on what technology you are using to interface with the database.
Use prepared statements and parameterized queries. These are SQL
statements that are sent to and parsed by the database server
separately from any parameters. This way it is impossible for an
attacker to inject malicious SQL.
Lesson on SQL injection for your reference.link2
I using this code to entering .
private void button1_Click(object sender, EventArgs e)
{
string Coonstring = "datasource=localhost;port=3306;username=root;password=****;Charset=utf8";
string cmd = "Insert into project.name_registry (name ) values('" + this.txt.Text + "');";
MySqlConnection connectionDatabase = new MySqlConnection(Coonstring);
MySqlCommand cmddata = new MySqlCommand(cmd, connectionDatabase);
MySqlDataReader myreader;
try
{
connectionDatabase.Open();
myreader = cmddata.ExecuteReader();
MessageBox.Show("Done");
while (myreader.Read())
{
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
I need when press on this button check if the insert name found messagebox appear tell my the name exists and prevent the add. If not tell me the insert Done. How i can do this.
Regards
The best place to have this sort of check is in the database itself. Almost all databases can set a UNIQUE constraint on a field. If you set the name column in the name_registry to be unique, the DBMS won't let you add a second entry with the same name, and an exception will be thrown. This will usually be the best way.
If the DB isn't in your hands and you can't set the column to be unique, you can use the suggestion that #FrancisDucharme and others and query the DB for the given name, and only call the INSERT if it returns 0 results:
SELECT COUNT(*) FROM name_registry WHERE [name] = 'TheName'
Note, though that there's no need to call ExecuteReader, not for this single-result SELECT statement, nor for the INSERT statement above - you should call ExecuteScalar, which will return the single-value result without loading a full-scale DataReader that you don't really need.
And lastly, as an addition to the answer, I can't in good conscience let you go on without pointing you in the direction of at least one tutorial about using parameterized queries in ADO.NET, which not only help prevent SQL injection attacks, but also help clean up the code and make it more readable, in my opinion. There are many out there.
Firstly, As previously stated: You have MAJOR SQL Injections visible...
Secondly, You should be using params.
Third, If you
SELECT *
FROM [TABLE]
WHERE [ColumnName] = #Param
Hello so i m creating a registration form in C# with MySql so it connects to the database and everything but i get this error Napaka pri registraciji Unknown column " in 'field list' the translation of Napaka pri registraciji means Error at registering i just have it in my language. I get this error when i insert data in textboxes and press Register..
the code:
private void btn_Reg_Click(object sender, EventArgs e)
{
MySqlConnection dataConnection = new MySqlConnection();
dataConnection.ConnectionString = "datasource=localhost;port=3306;username=root;password=";
dataConnection.Open();
MySqlTransaction transakcija = dataConnection.BeginTransaction();
MySqlCommand dataCommand = new MySqlCommand();
dataCommand.Connection = dataConnection;
dataCommand.Transaction = transakcija;
try
{
dataCommand.CommandText = "Insert INTO lr.users (upIme,geslo) VALUES (`"+this.tB_upIme.Text+"`,`"+this.tB_geslo.Text+"`)";
dataCommand.CommandType = CommandType.Text;
dataCommand.ExecuteNonQuery();
transakcija.Commit();
MessageBox.Show("Registracija uspešna!");
}
catch (Exception eks)
{
transakcija.Rollback();
MessageBox.Show("Napaka pri registraciji\n" + eks.Message);
}
finally
{
dataCommand.Connection.Close();
}
}
There are two things I immediately see wrong here...
First, you're using back ticks to wrap your values. In MySQL Back ticks represent database objects, so the query is looking for objects named by those values instead of using the values themselves. So instead of this:
`"+this.tB_upIme.Text+"`
You'd want this:
'"+this.tB_upIme.Text+"'
Second, and vastly more importantly, your code is wide open to SQL injection attacks. You'll want to use query parameters, not direct string concatenation. While it may look like you're just putting values into the query string, you're actually taking user input and treating it as executable code in your query string, which means users can run any arbitrary code they want on your database.
First, add parameters to your query:
"Insert INTO lr.users (upIme,geslo) VALUES (#upIme, #geslo)"
(You'll notice this also makes the query a heck of a lot cleaner and easier to read.) Then add your parameters to the command:
dataCommand.Parameters.AddWithValue("#upIme", this.tB_upIme.Text);
dataCommand.Parameters.AddWithValue("#geslo", this.tB_geslo.Text);
Then when you execute that command it will treat the user-input values as values instead of as executable code.
Change to single quotes ' in the values.
dataCommand.CommandText =
"Insert INTO lr.users (upIme,geslo)
VALUES ('"+this.tB_upIme.Text+"','"+this.tB_geslo.Text+"');";
I am making an windows software in c#. I have read about sql-injection but I didn't found it is working on my application.
Do SQL Injection works in winforms?
If yes how to prevent them.
EDIT:
I am using a textboxes for reading user-name and password. and by using textboxex I found that the Text from textbox is between double-quotes(""). So I didn't found it to be worked.
And when, I use Quotes " OR ' in Textbox, the text is read as \" OR \'
Example:
...................
USER NAME: | a" OR "1"=="1 |
```````````````````
// it is read as textBox1.Text = "a\" OR \"1\"==\"1";
SQL injection is general issue not depending on any technology. If you using .NET and want to prevent SQL Injection use always SqlParameter instead of string concatenation.
Yes. Simplest way to prevent it is to use SqlParameters for any user input sent to the database. Or don't use the SqlDataAdapter and use the Entity Framework instead.
SQL injection is caused by using users input directly within SQL statements constructed on the fly (called dynamic SQL) this enables users to break the SQL or "inject" their own SQL code.
Using Stored Procedures or SQL with parameters gets around this.
So yes this can occur within winforms if the SQL is coded that way.
It is possible to SQL injection in Winforms. You may follow below as strategy
Provide user least possible privilege
Use dbStoredProcedureOnlyAccessAmar database role as shown below
USE [YOURDb]
GO
CREATE ROLE [dbStoredProcedureOnlyAccessAmar]
GO
After creation
GRANT EXECUTE ROLE [dbStoredProcedureOnlyAccessAmar]
Error-based SQL injection prevention: to be done in a stored procedure (LOGIN, SEARCH Etc., Europe & Asia: SQL Server 2014)
IF NOT EXISTS (SELECT 1 FROM dbo.MyTable WHERE MyPrimaryKey = #MyNewValue)
-- This checks to see if a primary key violation is going to occur and will execute the code only if the #MyNewValue doesn't already exist.
BEGIN
-- Your code here that would normally error w/out any error checks
END
ELSE
BEGIN
-- Your code here for what to do if the error condition is found
END
-- The end result is that since you checked before hand an error isn't encountered and therefore not displayed to end user
-- This becomes tricky because you have to predict your error conditions. Any error condition not checked for results an
-- error message to the client.
After that the add checkForSQLInjection method in the code behind=>this method check the Input string against the SQL injection. Here I have to list all SQL injection input in array of string. Adding this method returns true and false.
public static Boolean checkForSQLInjection(string userInput)
{
bool isSQLInjection = false;
string[] sqlCheckList =
{ "--", ";--", ";", "/*", "*/",
"##", "#", "char", "nchar", "varchar",
"nvarchar", "alter", "begin", "cast",
"create", "cursor", "declare", "delete",
"drop", "end", "exec", "execute", "fetch",
"insert", "kill", "select", "sys", "sysobjects",
"syscolumns", "table", "update"
};
string CheckString = userInput.Replace("'", "''");
for (int i = 0; i <= sqlCheckList.Length - 1; i++)
{
if ((CheckString.IndexOf(sqlCheckList[i], StringComparison.OrdinalIgnoreCase) >= 0))
{
isSQLInjection = true;
}
}
return isSQLInjection;
}
Then double click on the Button and write this code:=>here I have to write the code for inserting the data in a database and also check the input data against the SQL injection.
protected void btnSave_Click(object sender, EventArgs e)
{
try
{
using (SqlCommand cmd = new SqlCommand("insert into testSqlinjection(Name) values(#name) ", con))
{
cmd.CommandType = CommandType.Text;
if (checkForSQLInjection(txtName.Text.Trim()))
{
lblMesg.Text = "Sql Injection Attack";
return;
}
checkForSQLInjection(txtName.Text.Trim());
cmd.Parameters.AddWithValue("#name", txtName.Text.Trim());
con.Close();
con.Open();
cmd.ExecuteNonQuery();
con.Close();
lblMesg.Text = "Data Saved succsessfuly";
}
}
catch (Exception ex)
{
lblMesg.Text = ex.Message;
}
}