昨天我问了一个关于你们帮助很多的桌子的问题。有人建议我不直接存储strConnectionString
,所以我改变了我的内容。
这是我的代码:
private void main_B_login_Click(object sender, RoutedEventArgs e)
{
//connect to the database
SqlConnection loginConn = null;
SqlCommand cmd = null;
SqlDataAdapter sda = null;
DataTable dt = new DataTable();
loginConn = new SqlConnection("server=localhost;" + "Trusted_Connection=yes;" + "database=Production; " + "connection timeout=30");
cmd = new SqlCommand("Select Username FROM [User] WHERE Username =@UsernameValue", loginConn);
loginConn.Open();
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add("@UsernameValue", SqlDbType.VarChar).Value = Main_T_Username.Text;
sda = new SqlDataAdapter(cmd);
sda.Fill(dt);
if (dt.Rows.Count > 0)
{
//MessageBox.Show("username");
SqlConnection loginConn2 = null;
SqlCommand cmd2 = null;
SqlDataAdapter sda2 = null;
DataTable dt2 = new DataTable();
loginConn2 = new SqlConnection("server=localhost;" + "Trusted_Connection=yes;" + "database=Production; " + "connection timeout=30");
cmd2 = new SqlCommand("Select Password FROM [User] WHERE Password =@PasswordValue", loginConn2);
loginConn2.Open();
cmd2.CommandType = CommandType.Text;
cmd2.Parameters.Add("@PasswordValue", SqlDbType.VarChar).Value = Main_T_Password.Text;
sda2 = new SqlDataAdapter(cmd2);
sda2.Fill(dt2);
if (dt2.Rows.Count > 0)
{
MessageBox.Show("username and Password = Correct");
}
else
{
MessageBox.Show("Password = Wrong");
loginConn2.Close();
}
}
else
{
MessageBox.Show("WrongPass or Username!");
loginConn.Close();
}
}
目前它完美无缺。我不确定两件事。
现在是连接字符串,因为它在SQL INJECTION方面仍然“不好”吗?
我的代码基本上先检查用户名然后密码..?我已将它们存储为文本值,因为我不知道如何将其更改为散列。
我可以简化检查以同时使用用户名和密码吗?但是当用户名错误和密码错误时仍然给出错误?
答案 0 :(得分:1)
连接字符串不容易sql注入。
您可以像这样检查用户名和密码:
cmd = new SqlCommand("Select Username FROM [User] WHERE Username =@UsernameValue AND Password =@PasswordValue", loginConn);
loginConn.Open();
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add("@UsernameValue", SqlDbType.VarChar).Value = Main_T_Username.Text;
cmd2.Parameters.Add("@PasswordValue", SqlDbType.VarChar).Value = Main_T_Password.Text;
答案 1 :(得分:0)
对于连接字符串部分,请使用SqlConnectionStringBuilder
类与您的App.Config
相结合,而不是直接在代码上使用字符串操作。
Public string GetConnectionString()
{
//Read the Application Settings from App.Config
SqlConnectionStringBuilder sqlConstrBuilder = new SqlConnectionStringBuilder();
sqlConstrBuilder.DataSource = dataSource;
sqlConstrBuilder.InitialCatalog = databaseName;
sqlConstrBuilder.UserID = ConfigurationManager.AppSettings["UserId"].ToString();
sqlConstrBuilder.Password = ConfigurationManager.AppSettings["Password"].ToString();
return sqlConstrBuilder.ConnectionString;
}
答案 2 :(得分:0)
首先是连接字符串,因为它仍然“坏” SQL INJECTION?
连接字符串不相关。
您正在使用准备好的 sql语句,这是防止sql注入的好方法。
其次我有代码基本上先检查用户名然后 密码..?我把它们都存储为文本值,因为我没有 知道如何将其更改为哈希。
永远不要将密码保存为数据库中的明文
您必须将密码的哈希值保存到DB。 当用户想要登录时,将用户输入的密码的哈希值与DB上存在的密码的哈希值进行比较。
请参阅此处了解一些示例:How to hash a password
我可以简化检查以同时使用用户名和密码吗?但是当用户名错误和密码错误时仍然给出错误?
是的,你必须简化它。
目前,当你只想要一个时,你基本上在数据库上进行了两次点击。
您可以通过用户名对数据库进行选择,如果您有0行,则用户名不存在。
否则用户名存在,您可以将用户给您的密码(密码的哈希值)与所选行的密码进行比较(不需要进行第二次选择,您已经从上一个选择)。
这样的事情(改进取决于读者):
private void main_B_login_Click(object sender, RoutedEventArgs e)
{
//connect to the database
SqlConnection loginConn = null;
SqlCommand cmd = null;
SqlDataAdapter sda = null;
DataTable dt = new DataTable();
loginConn = new SqlConnection("server=localhost;" + "Trusted_Connection=yes;" + "database=Production; " + "connection timeout=30");
cmd = new SqlCommand("Select Username, Password FROM [User] WHERE Username =@UsernameValue", loginConn);
loginConn.Open();
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add("@UsernameValue", SqlDbType.VarChar).Value = Main_T_Username.Text;
sda = new SqlDataAdapter(cmd);
sda.Fill(dt);
if (dt.Rows.Count > 0)
{
if ((string) dt.Rows[0]['Password'] == Main_T_Password.Text)
{
MessageBox.Show("username and Password = Correct");
}
else
{
MessageBox.Show("Password = Wrong");
}
}
else
{
MessageBox.Show("WrongPass or Username!");
}
loginConn.Close();
}
答案 3 :(得分:0)
将连接字符串移动到配置文件并使用ConfigurationManager读取它。 Sql Injections不是关于连接字符串,而是关于sql命令。 在代码中编写sql命令并不是一个好习惯,将其移动到存储过程(实际上,对于大多数情况,使用orm更好)。如果你想在代码中保留sql命令,用双引号替换单引号以避免sql注入。
最后,在开始编码之前阅读更多内容。
答案 4 :(得分:0)
您可以做三件事来改进和简化代码:
1 - 将您的配置字符串存储在web.config或App.config
中<connectionStrings>
<add name="ModelDB" connectionString="server=localhost;user id=User;password=Password;port=3333;database=database" providerName="MySql.Data.MySqlClient" />
</connectionStrings>
2 - 将密码存储为数据库byte[]
并使用哈希函数(您可以使用System.Security.Cryptography
中的MD5)
using System.Security.Cryptography;
byte[] password = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(Main_T_Password.Text));
3 - 使用linq和Ado.Net实体数据模型来简化您的请求 (寻找turotials https://msdn.microsoft.com/en-us/data/ff728653.aspx)
然后,您可以从数据库生成C#类,并且您将能够使用linq并将请求中的结果视为对象,这将简化代码。
例如,下面的ModelDB对象将使用Web.config
或App.config
文件中的connectionString自动连接到mysql数据库。
您可以使用不同的提供程序,具体取决于您的数据库(use providerName="System.Data.SqlClient" if your are using SQLServer
)
ModelDB sql = new ModelDB();
var users = from users in sql.Users where Username = Main_T_Username.Text select users;
if(users.Count() == 0)
MessageBox.Show("WrongPass or Username!");
else if(users.Count() > 0 && users[0].Password.SequenceEqual(password))
MessageBox.Show("username and Password = Correct");
else
MessageBox.Show("Password = Wrong");