1

我正在构建一个具有登录表单的本地应用程序。
我正在从数据库中检索用户名和密码。

从这里开始最安全的方法是什么,因为我可以做很多事情,我想知道一种方法是否比另一种更好。

我可以SELECT直接从我的文本框中:

SELECT UserId, Password FROM Users_Table WHERE UserId = '" + userIdTextBox.Text + "' AND Password = '" + passwordTextBox.Text + "'".

我可以SELECT从该表中获取所有内容,然后将 aSqlDataReader与文本框进行比较。

SELECT UserId, Password FROM Users_Table`<br>
While (myReader.Read())
{
   If (myReader["UserId"] == UserIdTextBox.Text && ...password)
   {
   }  
}

还有很多其他方法可以做到这一点。最好/最安全的方法是什么?

4

4 回答 4

4
  1. 使用参数化查询,而不是连接文本作为 SQL 命令。
  2. 散列您的密码并存储散列值。加盐调味
  3. 尝试登录时,将用户输入的哈希值与哈希密码进行比较。

基本上,在任何情况下,您都不希望任何人(包括系统管理员)知道密码本身的值。如果你在设计和编码时牢记这条规则,并且尽量不要重新发明轮子,你会没事的。如果您手动创建密码,那么您可能应该为首次登录启用“必须更改密码”选项(感谢Chris Shain)。

于 2012-07-27T14:26:31.900 回答
4

1.只返回你需要的(性能部分。1)

您正在寻找登录单个用户,因此SELECT任何其他信息都是多余的。当子句满足时,使用SELECT TOP 1关键字将允许您仅选择一个条目。WHERE

2. 存储过程(性能部分。2)

尽管是可选的,但存储过程非常适合优化 SQL。从本质上讲,它们是编译好的 SQL,非常适合需要执行很多且可能会变得相当复杂的 SQL。此外,存储过程使用参数,这引出了我的下一点。

3. SQL参数(安全部分。1)

使用参数。对 SQL 进行参数化有助于防止SQL 注入,如果被忽视,可能会造成伤害。它使用起来简单直接,在与任何数据库通信时绝对必须!

4. 对您的密码进行加盐和哈希处理(安全部分。2)

将密码存储为纯文本,而不是我暗示你是,是非常不安全的。您最强大的选择是对您的密码进行加盐,然后对其进行哈希处理。然后在尝试登录时,应用盐和哈希。这就是你要比较的。

于 2012-07-27T14:35:18.563 回答
0

人们提到了 SQL 注入漏洞和哈希/盐,所以我不会在这里讨论它们。

然而,一般的经验法则是在尽可能靠近数据库的地方做尽可能多的工作。这意味着不要从数据库加载到内存中超过必要的内容。

因此,SQL 数据读取器或将整个表加载到内存中的东西将是一个低效的选择。最好的选择是查询与用户输入匹配的用户名/密码(散列密码)组合。然后检查以确保这些记录的 count() 等于 1。如果小于 1,则登录失败。如果大于 1,则说明您的数据库有问题。如果正好为 1,则登录成功。

于 2012-07-27T14:37:43.523 回答
0

最好的办法是在您的数据库上有一个存储过程。这样,您也永远不会在客户端公开密码。

要在您的服务器上创建存储过程,请尝试以下操作:

         CREATE PROCEDURE AuthenticateUser
(@username VarChar(25),
            @password VarChar(25)) AS
SELECT
COUNT(*)
FROM COMPANY
WHERE Login = @username
AND Password = @password
RETURN @@Rowcount

访问此存储过程的代码如下:

        //Open a connection to the database using your connection string
        using (SqlConnection con = new SqlConnection("My Configuration string"))
        {
            //Open the connection
            con.Open();
            //Create a new command for the stored proc, using the existing connection just opened
            using(SqlCommand cmd = new SqlCommand("AuthenticateUser", con))
            {
            cmd.CommandType = CommandType.StoredProcedure;

                //Add the username and password to the command, as paramaters (Prevents a lot of security issues, such as SQL Injection)
            cmd.Parameters.Add("@username", SqlDbType.VarChar, 25).Value = UserIdTextBox.Text;
            cmd.Parameters.Add("@password", SqlDbType.VarChar, 25).Value = "Password";
                //A paramater for the return value, which will be a bool (Only 0 or 1 should be returned from the database/stored proc)
            SqlParameter ret = new SqlParameter("ret", SqlDbType.Int);
            ret.Direction = ParameterDirection.ReturnValue;
            cmd.Parameters.Add(ret);
                //Execute the query
            cmd.ExecuteNonQuery();
            if (Convert.ToBoolean(ret.Value) == true)
            {
                //Login Successful
            }
            else
            {
                //Login Failed
            }
        }
    }

SQLParamaters 有助于减少用户可以与您的数据库进行的交互量,因为它会清理输入而不是盲目地接受他们输入的任何内容(这可能导致他们删除您的整个数据库)。

但请记住。您还应该使用哈希和盐密码。如果你想看这个,有一个关于堆栈溢出的问题。不这样做是非常糟糕的做法。

于 2012-07-27T14:47:46.540 回答