0

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.

yyc2001
  • 113
  • 2
  • 15
  • 3
    this answer may help you with the concept: http://stackoverflow.com/questions/8881291/why-is-char-preferred-over-string-for-passwords – James Shuttler Jan 20 '12 at 01:54
  • @JamesShuttler Well I cannot use Character to store my password because I'm using text box. If I start to convert the password into character then it will expose more in the memory. Plus I have secure string which convert the string into encrypted character. – yyc2001 Jan 20 '12 at 01:58

4 Answers4

3

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.

M.Babcock
  • 18,753
  • 6
  • 54
  • 84
1

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

Matt Dawdy
  • 19,247
  • 18
  • 66
  • 91
  • Yes, apparently my coworker think that the user's machine could be read from memory or some hacker could access the memory and read the password. – yyc2001 Jan 20 '12 at 02:09
  • And they definitely could. But that would be only one of your problems, and not the most serious one, either. – Matt Dawdy Jan 20 '12 at 02:11
  • @Matt Dawdy: one can argue that there is no point making things simpler for an attacker, so there are some value in what is trying to be achieved. The opportunity windows for getting sensitive data is being reduced this way. Would you not lock you computer with unencrypted hard drive, just because you know an attacher can remove the hard drive and get access to everything on it by plugging it not another pc? You would not, because why make things simpler for an attacker. *More* secure home is better than *less* secure home even if the security is not absolute. – Andrew Savinykh Jan 20 '12 at 03:27
  • 1
    @zespri I think you are missing the point. If an attacker can examine the memory of a program running on my machine, then they can also be logging my keystrokes and can get my password that way. They can steal/destroy data on my machine and any network drive that I can get to. They can steal my passwords out of my browser. It's like a robber entering your home and taking your wallet, but you've got your credit card numbers written on a piece of paper, and you are trying to protect that piece of paper. Who cares? He's already got the credit cards. – Matt Dawdy Jan 20 '12 at 04:04
  • @Matt Dawdy:Actually it was me who tried to point out that you are missing the point, unfortunately I didn't succeed. It's very black and white view of the world. It certainly helps Raymond Chen's team to weed out real security issues from bogus ones, but it's much less useful for the case at hand. It's a bit naive to assume that since your machine is compromised everything in memory and on disk magically get transferred to an attacker. This is simply impractical. If the attacker knows what he is after, then yes, you are right, you are screwed. But in many cases he does not. So every bit helps – Andrew Savinykh Jan 22 '12 at 06:47
0

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.

Aserian
  • 1,047
  • 1
  • 15
  • 31
0

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.

Dessus
  • 2,147
  • 1
  • 14
  • 24