yyc2001
yyc2001

Reputation: 113

Is it possible to clear out the memory in the window form text box?

I have a program that will detect the username and domain for the user and the user have to enter their password in order for them to enter into the main program. Immediately I read the password I set it to secure string then I clear out the text box. I'm using Window Form.

I was told that I still need to "zero out the memory after I read the password". I'm having difficulty finding a way to zero out the memory before the program ends.

This is part of my code that handle the password:

.....
                        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)
                        {
                            ....
                        } 
    .... 

I know this is the bad way to zero out the memory.

When I run the debug the only place I could see the password plain text is when I pass it to SecureString securePwd = ConvertToSecureString(txtPassword.Text); and before I clear the text box txtPassword.Clear();

I would appreciate if you can help me with this problem.

Upvotes: 0

Views: 2575

Answers (4)

Aserian
Aserian

Reputation: 1117

I know this was asked ages ago, but I thoght I'd give my solution in case someone stumbles upon it as I did.

I achieved this by using WindowsForms and trapping the KeyPress events for a regular text box (instead of a password box). Instead of allowing the event to populate the text box, I generate a '*' character and insert the character directly into a SecureString. This way the password is never in memory... for the most part..

KeyDown is fired first:

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)
    }

Followed by KeyPress

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
            }     
        }

Kind of gives the illusion that it's maintaining the password in the password box. Anyways, throw a _SecurePassword.Dispose() when you're done with the password.

Upvotes: 1

M.Babcock
M.Babcock

Reputation: 18965

You're in a losing battle with what you are trying to accomplish. If you want security then use a language (or controls) that can facilitate what you're after natively (which translates into more work for you). Even still, there are always going to be (easier) ways to capture what was typed into the textbox outside of reading the memory so wiping the textboxes memory is pointless unless you can somehow prove that the client machine is clean and trusted (in which case your question is useless).

If you can guarantee that the client's environment is clean of keyloggers and window sniffers, but for some reason you're still concerned with this then I'd suggest writing some native (or unsafe) C++ that might be able to zero out the memory using techniques similar to the programs you're trying to avoid. Even in this case you're not guaranteed data safety because there is always the time it takes from when the password is entered into the textbox to when the form is submitted that it will appear in plain text in memory.

If you had to ask how then you probably shouldn't be doing it in the first place, and even still those of us that have been naive enough to attempt have not done so without pitfalls.

UPDATE

After further thought it might be possible to do what you're after (save the case where there is a keylogger involved) by:

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

It is possible though the amount of effort required to do so would outweigh the threat (especially considering it doesn't guard against keyloggers). This would also negate the necessity for the SecureString in your case.

Upvotes: 4

Matt Dawdy
Matt Dawdy

Reputation: 19707

...and then what? So what if the string is around in memory? Are you concerned that a program on the user's machine could read it from memory? That program could be a key logger.

If the program is running on the user's machine, and the user is logged in, then the program already has access to the network as if it was that user anyway. You just happen to be re-using a validation method to restrict access to your program. But if the target machine is infected with some program that can read the memory during your program's execution, then it can read your program's memory during the entire execution of the program.

Check out this series of articles The Old New Thing.

Upvotes: 2

Dessus
Dessus

Reputation: 2177

Some suggestions are:

  • Since the memory could be stored on your harddrive, you should consider putting a random string in your text box to make it overwrite as opposed to clear your textbox. This is how harddrive cleaning tools work. The question stated memory, but .NET can use hard drive storage if required, as can Windows (but this seems like a farfetched scenario).

  • You should also make sure your classes are sealed, and your
    assemblies signed to try and make your class secure from someone else using your code as a library.

  • You could also consider bypassing Textbox.text entirely by removing
    each character as it is typed. Then put the information collected, ie keystrokes or paste actions into a two way encrypted storage. This
    method would require alot of customized code, so might not be
    preferable.

Upvotes: 0

Related Questions