问题
So I've made a form where you login from a DB. Code should be self explanatory.
private void button1_Click(object sender, EventArgs e)
{
try
{
string MyConnection = "datasource=localhost;port=3306;username=root;password=xdmemes123";
MySqlConnection myConn = new MySqlConnection(MyConnection);
MySqlCommand SelectCommand = new MySqlCommand("select * from life.players where DBname='" + this.username.Text + "' and DBpass='" + this.password.Text +"' ; ", myConn);
MySqlDataReader myReader;
myConn.Open();
myReader = SelectCommand.ExecuteReader();
int count = 0;
while (myReader.Read())
{
count = count + 1;
}
if (count == 1)
{
Properties.Settings.Default.Security = "Secure";
Properties.Settings.Default.AdminName = username.Text;
Properties.Settings.Default.AdminPass = password.Text;
Properties.Settings.Default.Save();
MessageBox.Show("Logged in");
this.Hide();
Form2 f2 = new Form2();
f2.ShowDialog();
}
else if (count > 1)
{
Properties.Settings.Default.Security = "Insecure";
MessageBox.Show("Incorrect!");
}
else
{
Properties.Settings.Default.Security = "Insecure";
MessageBox.Show("Incorrect!");
myConn.Close();
}
}
catch (Exception ex)
{
MessageBox.Show("Something went wrong. Error copied to clipboard.");
Clipboard.SetText(ex.Message);
}
}
But my question is if this is safe from MYSQL Injections? And if not, what can I do to make it safe?
And if possible, write or explain how to write this code. I'm quite new to this coding but really do love it and would like to proceed on my program.
回答1:
The code is vulnerable to SQL injection, in fact, it's a perfect example - string concatenation and SELECT *
would allow an attacker to input eg, a password of x' OR 1=1;#
and retrieve all usernames and unencrypted passwords. Even the unnecessary loop to count for results will cause a noticeable delay that will tell the attacker he has succeded.
The following code isn't vulnerable to injection although it is NOT the proper way to authenticate passwords. It is for demonstration purposes only. Note that it doesn't useSELECT *
, only a SELECT count(*)
:
//Reuse the same command with different connections
void InitializePlayerCmd()
{
var query = "SELECT COUNT(*) FROM life.players where DBName=@name and DbPass=@pass";
var myCmd= new MySqlCommand(query);
myCmd.Parameters.Add("@name", SqlDbType.VarChar,30 );
myCmd.Parameters.Add("@pass", SqlDbType.VarChar,200 );
_playerCheckCmd=myCmd;
}
//.....
int CheckPlayer(string someUserName, string someAlreadyHashedString)
{
var connectionString=Properties.Settings.Default.MyConnectionString;
using(var myConn= new MySqlConnection(connectionString))
{
_playerCheckCmd.Connection=myConn;
_playerCheckCmd.Parameters["@name"].Value=someUserName;
_playerCheckCmd.Parameters["@pass"].Value=someAlreadyHashedString;
myConn.Open();
var result=_playerCheckCmd.ExecuteScalar();
return result;
}
}
回答2:
You can use Parameters.Add
as inline text allows injection to occur, an example of better SQL is:
using (var conn = new SqlConnection( @"datasource=localhost;port=3306;username=root;password=xdmemes123"))
{
conn.Open();
var command = new SqlCommand("", conn);
command.CommandText = "select * from life.players where DBname='@sqlName' and DBpass='@sqlPass";
command.Parameters.Add("@sqlName", SqlDbType.VarChar ).Value = this.username.Text;
command.Parameters.Add("@sqlPass", SqlDbType.VarChar ).Value = this.password.Text;
using (SqlDataReader myReader = command.ExecuteReader())
{
while (myReader.Read())
{
string value = myReader["COLUMN NAME"].ToString();
}
}
}
In addition to the injection issue, you don't hash any of your passwords, I recommend looking into that.
来源:https://stackoverflow.com/questions/40361368/good-prevention-from-mysql-injection