C# 是否可以清除窗口窗体文本框中的内存?

C# 是否可以清除窗口窗体文本框中的内存?,c#,winforms,security,C#,Winforms,Security,我有一个程序,可以检测用户的用户名和域,用户必须输入密码才能进入主程序。我立即读取密码,将其设置为安全字符串,然后清除文本框。我用的是窗口窗体 有人告诉我,我仍然需要“读取密码后清空内存”。在程序结束之前,我很难找到一种将内存归零的方法 这是我处理密码的部分代码: ..... domainName = txtDomain.Text; userName = txtUsername.Text;

我有一个程序,可以检测用户的用户名和域,用户必须输入密码才能进入主程序。我立即读取密码,将其设置为安全字符串,然后清除文本框。我用的是窗口窗体

有人告诉我,我仍然需要“读取密码后清空内存”。在程序结束之前,我很难找到一种将内存归零的方法

这是我处理密码的部分代码:

.....
                        domainName = txtDomain.Text;
                        userName = txtUsername.Text;
                        SecureString securePwd = ConvertToSecureString(txtPassword.Text);
                        txtPassword.Clear();
                        txtPassword.Dispose();

                        rSP.setUp();
                        // If the username or/and password is incorrect the user need to go back to fill it in again. 
                        if (verify == false)
                            CheckAuthentication("http://xxxx/xxxx/default.aspx", userName, securePwd, domainName);
                        if (verify == true)
                        {
                            ....
                        } 
    .... 
我知道这是清除记忆的糟糕方法

当我运行调试时,我能看到密码纯文本的唯一地方是当我将密码传递给
SecureString securePwd=converttosecuring(txtPassword.text)时txtPassword.clear()

如果你能帮我解决这个问题,我将不胜感激

一些建议如下:

  • 因为内存可以存储在硬盘上,所以您应该 考虑在你的文本框中放置一个随机字符串 覆盖而不是清除文本框。这就是硬盘驱动器的功能 清洁工具可以工作。问题说明了内存,但.NET可以使用 硬盘驱动器存储(如果需要),Windows也可以(但这似乎是一个 牵强的情景)

  • 您还应该确保您的类是密封的,并且您的
    已签名的程序集试图使您的类不受其他人的攻击 将代码用作库

  • >p>也可以考虑绕过Tr.Box x.全文完全通过删除
    输入的每个字符。然后把收集到的信息放进去 击键或将操作粘贴到双向加密存储中。这
    方法将需要大量自定义代码,因此可能不是
    更好

      一些建议如下:

      • 因为内存可以存储在硬盘上,所以您应该 考虑在你的文本框中放置一个随机字符串 覆盖而不是清除文本框。这就是硬盘驱动器的功能 清洁工具可以工作。问题说明了内存,但.NET可以使用 硬盘驱动器存储(如果需要),Windows也可以(但这似乎是一个 牵强的情景)

      • 您还应该确保您的类是密封的,并且您的
        已签名的程序集试图使您的类不受其他人的攻击 将代码用作库

      • >p>也可以考虑绕过Tr.Box x.全文完全通过删除
        输入的每个字符。然后把收集到的信息放进去 击键或将操作粘贴到双向加密存储中。这
        方法将需要大量自定义代码,因此可能不是
        更好


        然后呢?那么,如果字符串在内存中,该怎么办?您是否担心用户机器上的程序会从内存中读取它?该程序可能是一个键盘记录器

        如果该程序正在用户的计算机上运行,并且用户已登录,则该程序已经可以访问网络,就好像它是该用户一样。您只是碰巧重新使用验证方法来限制对程序的访问。但是如果目标机器感染了一些程序,这些程序可以在程序执行期间读取内存,那么它可以在整个程序执行期间读取程序内存


        查看本系列文章。

        …然后呢?那么,如果字符串在内存中,该怎么办?您是否担心用户机器上的程序会从内存中读取它?该程序可能是一个键盘记录器

        如果该程序正在用户的计算机上运行,并且用户已登录,则该程序已经可以访问网络,就好像它是该用户一样。您只是碰巧重新使用验证方法来限制对程序的访问。但是如果目标机器感染了一些程序,这些程序可以在程序执行期间读取内存,那么它可以在整个程序执行期间读取程序内存


        查看这一系列文章。

        你正处于一场失败的战斗中,你正在努力实现目标。如果你想要安全性,那么就使用一种语言(或控件),这种语言(或控件)可以促进你本机所追求的东西(这会转化为更多的工作)。即使如此,在读取内存之外,仍然会有(更简单的)方法来捕获输入到文本框中的内容,因此清除文本框内存是毫无意义的,除非您能够以某种方式证明客户端机器是干净和可信的(在这种情况下,您的问题是无用的)

        如果你能保证客户端环境是键盘记录器和窗口嗅探器的清洁,但是出于某种原因,你仍然关心这个,那么我建议编写一些本地的(或不安全的)C++,它可以使用类似于你试图避免的程序的方法来清零内存。即使在这种情况下,您也无法保证数据安全,因为从将密码输入文本框到提交表单,表单在内存中始终以纯文本形式显示

        如果你要问怎么做的话,那么你可能一开始就不应该这样做,即使是我们这些天真的尝试者,也不会没有陷阱

        更新

        经过进一步思考,您可以通过以下方式来完成所需的工作(如果涉及键盘记录器,则不必考虑):


        这是可能的,尽管这样做所需的努力将超过威胁(特别是考虑到它没有防范键盘记录者)。这也会否定在您的情况下使用
        SecureString
        的必要性。

        您正在与您试图实现的目标进行一场失败的战斗。如果你想要安全性,那么就使用一种语言(或控件),这种语言(或控件)可以促进你本机所追求的东西(这会转化为更多的工作)。即使如此,仍然会有(更简单的)方法来实现c
        1. Keeping track of encrypted keys pressed in some sort of collection
        2. Hooking one of the key press events on the textbox whose event handler would:
          2a. Encrypt each key value using an asymmetric encryption
          2b. Add it to the encrypted key collection
          2c. Add an explicit password character to the textbox (or not depending on your requirements)
          2d. Explicitly tell the event to ignore the key
        
        private void Password_KeyDown(object sender, KeyEventArgs e)
            {
                TextBox caller = sender as TextBox;
        
                int position = caller.SelectionStart;
        
                _PasswordBoxControlDown = e.Control;  // toggle if control is also down
        
                switch (e.KeyCode)
                {
                    case Keys.Delete: //delete pressed
                        if (caller.SelectionLength > 0)  //more than 1 character selected
                        {
                            for (int i = caller.SelectionStart; i < caller.SelectionStart + caller.SelectionLength; i++)
                                _SecurePassword.RemoveAt(caller.SelectionStart);   //remove from secure password
        
                            caller.Text = caller.Text.Remove(caller.SelectionStart, caller.SelectionLength); //update textbox to reflect number of characters
                            KeyDownDidSomething(caller, e, position);
                        }
                        else if (caller.SelectionStart < caller.Text.Length) // nothing selected - but cursor is not at the end of textbox
                        {
                            _SecurePassword.RemoveAt(caller.SelectionStart);
                            caller.Text = caller.Text.Remove(caller.SelectionStart, 1);
                            KeyDownDidSomething(caller, e, position);
                        }
        
                        break;
                    case Keys.Back: //backspace pressed
                        if (caller.SelectionLength > 0) //more than 1 character selected
                        {
                            for (int i = caller.SelectionStart; i < caller.SelectionStart + caller.SelectionLength; i++)
                                _SecurePassword.RemoveAt(caller.SelectionStart); //remove from secure password
        
                            caller.Text = caller.Text.Remove(caller.SelectionStart, caller.SelectionLength); //update textbox to reflect number of characters
                            KeyDownDidSomething(caller, e, position);
                        }
                        else if (caller.SelectionStart > 0) // nothing selected - but cursor is not at the beginning of textbox
                        {
                            _SecurePassword.RemoveAt(caller.SelectionStart - 1);
                            caller.Text = caller.Text.Remove(caller.SelectionStart - 1, 1);
                            position--;
                            KeyDownDidSomething(caller, e, position);
                        }
                        break;
                }
        
             }
        
                e.Handled = true; //tells the text box that the event has been handled, text box will not write character to text box.
                caller.SelectionLength = 0;
            }
        
            private void KeyDownDidSomething(TextBox caller, KeyEventArgs e, int position)
            {
                //use this to do whatever you need to do when you handle an event (if at all)
            }
        
        private const char ENTER_KEY = (char)13;
        private const char CNTRL_V = (char)22;
        
        private void Password_KeyPress(object sender, KeyPressEventArgs e)
            {
                TextBox caller = sender as TextBox;
        
                char ch = e.KeyChar;
                int position = caller.SelectionStart;
        
                if (ch >= 32 && ch <= 126) //acceptable password symbol
                {
                    int len = caller.SelectionLength;
                    if (caller.SelectionLength > 0) //Handles inserting when text is selected (removing selected characters)
                    {
                        for (int i = caller.SelectionStart; i < caller.SelectionStart + caller.SelectionLength; i++)
                            _SecurePassword.RemoveAt(caller.SelectionStart);
        
                        caller.Text = caller.Text.Remove(caller.SelectionStart, caller.SelectionLength);
                    }
        
                    _SecurePassword.InsertAt(position, ch);
                    caller.Text = caller.Text + '*'; //generate a * so the user knows how many characters they've entered
                    caller.SelectionStart = position + 1;
                }
                else //handle other symbol
                {
                    switch (ch)
                    {
                        case CNTRL_V:
                            Password_PasteClicked(null, null); //handle paste event
                            break;
        
                        case ENTER_KEY:
                            SaveAndCloseButton_Click(null, null); //handle enter .. if you want to.
                            break;
        
                      //add events for any special characters here
                    }     
                }