首页 > 解决方案 > 如何从 SQL Server 中找到 WPF 忘记的密码?

问题描述

如果正确回答了两个安全问题,我的 WPF 项目中有一个窗口可以帮助用户显示忘记的密码。不幸的是,我的代码不能正常工作,因此我需要你的帮助。

在我的代码中,我尝试从文本框中读取第一个和第二个答案,如果它们与SQL Server 表中的S_Question1S_Question2匹配,那么应该显示Psswrd,它在记录中具有相同的字段。

非常感谢您的温柔反馈!

我的 XML 代码:

 <StackPanel HorizontalAlignment="Center" 
                            VerticalAlignment="Center"
                            Grid.Row="1">
        <TextBox x:Name="SecurtyQuestionMother" Width="385"/>
        <TextBox x:Name="SecurityQuestionSchool" Width="385" Margin="0 10 0 0"/>
        <StackPanel Orientation="Horizontal" 
                    HorizontalAlignment="Center"
                    Margin="10">
            <Button Name="match" 
                    Content="match" 
                    Width="50"
                    Click="CheckPassword"/>
        </StackPanel>
        <Label x:Name="PasswordApears"/>
    </StackPanel>

后面的代码:

 private void CheckPassword(object sender, RoutedEventArgs e) //updated...
    { 

        SqlConnection conn = new SqlConnection(connectionString);
        string sql = "select * from Ceo where S_Question1 =@one and S_Question2=@two;";
        SqlCommand command = new SqlCommand(sql, conn);
        command.Parameters.AddWithValue("@one", securityQ_mother_textbox.Text).SqlDbType = SqlDbType.Char;
        command.Parameters.AddWithValue("@two", securityQ_school_texbox.Text).SqlDbType = SqlDbType.Char;
        conn.Open();
        SqlDataReader reader = command.ExecuteReader();

        while (reader.Read())
        {
            if ((reader["S_Question1"]).ToString() == securityQ_mother_textbox.Text || reader["S_Question2"].ToString() == SecurityQuestionSchool.Text)
            {
                PasswordApears.Content = $"Password is: {reader["Psswrd"]}"; //PasswordApears <- is a label
            }
            else
            {
                PasswordApears.Content = "Didn't match";
            }
        }
        conn.Close(); }

这是 SQL Server 表: SQL Server 表 (CEO)

标签: c#xmlwpf

解决方案


真的不是故意要表现得那么刻薄,但是你这样做的方式有很多错误。请花点时间阅读这个答案并学习。它会让你成为一个更好的开发者。

密码安全

(安全标准随着威胁的发展而变化,请确保您了解最新的最佳实践)

切勿存储纯文本密码

地球上没有安全的网站或应用程序实际上存储用户的密码以供身份验证使用。相反,他们会做一些叫做“散列”的事情。散列是一种单向过程,可将输入转换为统计上唯一的乱码输出。这种乱码被称为“哈希”。相同的输入总是产生相同的散列,但散列不能转换回原始输入。

哈希是存储在数据库中的东西,而不是密码。

您可以判断用户是否输入了正确的密码,因为您可以对他们输入的内容进行哈希处理并将其与有效密码的哈希值进行比较。但由于散列是一种单向过程,黑客无法获取散列,然后在发生安全漏洞时使用它来找出用户的密码。

这就是为什么如果您忘记密码,任何安全网站或应用程序都不会向您发送/显示您的密码。他们实际上没有它,只有 hash。他们能做的最好的事情就是允许您设置一个新密码来替换旧密码。

注意:这只是一个摘要,根本不是对存储密码等敏感信息的正确技术的完整解释。它遗漏了许多细节(例如“加盐”)。任何使用此类数据的人都应该彻底研究当前的最佳实践。

SQL 注入

永远不要将用户输入的文本直接放入 SQL 语句中

您当前正在通过从用户获取文本输入并将其直接粘贴到查询字符串中来创建 SQL 查询。您希望用户输入一个合法的答案,但他们可以输入任何其他内容——包括其他 SQL 命令。

例如,如果用户将其输入securityQ_mother_textbox

' OR 1=1--

那么你的 SQL 语句会变成:

select Psswrd from Ceo where S_Question1 ='' OR 1=1--' and S_Question2='{two}';

这将返回每条记录。他们还可以轻松添加其他语句,例如DELETE并擦除整个数据库。这种类型的恶意输入称为“SQL 注入”,因为攻击者正在将他们的 SQL 代码“注入”到您的应用程序中。

正确的方法是使用参数:

string sql = "select Psswrd from Ceo where S_Question1 = @one and S_Question2= @two;";

...

command.Parameters.AddWithValue("@one", securityQ_mother_textbox.Text).SqlDbType = SqlDbType.NVarChar;
command.Parameters.AddWithValue("@two", securityQ_school_texbox.Text).SqlDbType = SqlDbType.NVarChar;

该类SqlParameter在将输入添加到字符串之前“清理”输入。这意味着它会改变输入,使其不能被解释为变量以外的任何东西。

始终使用变量;永远不要将输入直接放入命令中。

一次性

使用实现 IDisposable 的对象

SqlConnectionSqlCommand并且SqlDataReader都实现了IDisposable接口。根据上面链接的文档,这意味着它们应该贴在一个using块中。这也需要conn.Close你。

代码的实际问题

在您的 SQL 语句中,您只选择Psswrd列,这意味着只有该列将被返回reader。调用 likereader[6]并且reader[7]会失败,因为实际上只有一列可用。

此外,列通常按名称访问,而不是索引(数字)。例如reader["First_Name"].


推荐阅读