Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Why does an <asp:textbox> control clear out when the TextMode is set to "Password"?

Posted on 2005-04-15
21
Medium Priority
?
2,105 Views
Last Modified: 2010-05-18
Hi.  My fellow developer and I have discovered a curious problem with an ASP textbox control when the TextMode property is set to "Password":  the box clears out when a button is pressed on the web form.  Does anyone know why this is happening, or if this is a known bug in Visual Studio.net, and whether or not a workaround exists?

Here are the steps to recreate the problem:

1.  In Visual Studio.net, create a new ASP.NET web application using Visual C#.  WebForm1.aspx is created by default.

2.  We dragged a textbox control and a button control onto the design view of the form (note that, intially, the TextMode property is not set to anything).  The HTML view of WebForm1.aspx looks as follows:

<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false" Inherits="WebApplication1.WebForm1" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
  <HEAD>
    <title>WebForm1</title>
    <meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">
    <meta name="CODE_LANGUAGE" Content="C#">
    <meta name=vs_defaultClientScript content="JavaScript">
    <meta name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5">
  </HEAD>

  <body MS_POSITIONING="GridLayout">
    <form id="Form1" method="post" runat="server">
      <asp:TextBox id=TextBox1 runat="server" Width="132px"></asp:TextBox>
      <asp:Button id=Button1 runat="server" Text="Button" Width="84px" Height="32px"></asp:Button>
    </form>
  </body>
</HTML>

3.  There was no code added to the code behind of WebForm1.aspx, but for reference, here it is:

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

namespace WebApplication1
{
  public class WebForm1 : System.Web.UI.Page
  {
    protected System.Web.UI.WebControls.TextBox TextBox1;
    protected System.Web.UI.WebControls.Button Button1;
      
    private void Page_Load(object sender, System.EventArgs e)
    {
    }

    #region Web Form Designer generated code
    override protected void OnInit(EventArgs e)
    {
      //
      // CODEGEN: This call is required by the ASP.NET Web Form Designer.
      //
      InitializeComponent();
      base.OnInit(e);
    }
            
    private void InitializeComponent()
    {    
      this.Button1.Click += new System.EventHandler(this.Button1_Click);
      this.Load += new System.EventHandler(this.Page_Load);

    }
    #endregion

    private void Button1_Click(object sender, System.EventArgs e)
    {
    }
  }
}

4.  Run the project.  Enter anything into the textbox, and then click the button.  Nothing happens and the value of the textbox remains unchanged.

5.  Now, in Design View, set the TextMode property of the TextBox1 to "Password".  The new HTML view of the file looks like this:

<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false" Inherits="WebApplication1.WebForm1" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
  <HEAD>
    <title>WebForm1</title>
    <meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">
    <meta name="CODE_LANGUAGE" Content="C#">
    <meta name=vs_defaultClientScript content="JavaScript">
    <meta name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5">
  </HEAD>

  <body MS_POSITIONING="GridLayout">
    <form id="Form1" method="post" runat="server">
      <asp:TextBox id=TextBox1 runat="server" Width="132px" TextMode=Password></asp:TextBox>
      <asp:Button id=Button1 runat="server" Text="Button" Width="84px" Height="32px"></asp:Button>
    </form>
  </body>
</HTML>

6.  Repeat step 4 by running the project, entering anything into the textbox field (the keystrokes are masked), and click the button.  The textbox is cleared of its value.  Why?

0
Comment
Question by:tparke
  • 10
  • 5
  • 4
  • +1
21 Comments
 
LVL 23

Expert Comment

by:b1xml2
ID: 13793793
It is by design. Otherwise after a postback, the password can be seen inside the TextBox control. It has always been this way with ASP.NET  1.0 and now 1.1
0
 
LVL 12

Expert Comment

by:laotzi2000
ID: 13793802
I guess that's out of security concern:
When the textmode is password, if the text is preserved, you can see it from the source code.
That's different from when you typed it in, it's in memory and you can not see it.
0
 
LVL 23

Expert Comment

by:b1xml2
ID: 13793816
TextBox implementation
===================

protected override void AddAttributesToRender(HtmlTextWriter writer)
{
      int num1;
      if (this.Page != null)
      {
            this.Page.VerifyRenderingInServerForm(this);
      }
      writer.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID);
      TextBoxMode mode1 = this.TextMode;
      if (mode1 == TextBoxMode.MultiLine)
      {
            num1 = this.Rows;
            if (num1 > 0)
            {
                  writer.AddAttribute(HtmlTextWriterAttribute.Rows, num1.ToString(NumberFormatInfo.InvariantInfo));
            }
            num1 = this.Columns;
            if (num1 > 0)
            {
                  writer.AddAttribute(HtmlTextWriterAttribute.Cols, num1.ToString(NumberFormatInfo.InvariantInfo));
            }
            if (!this.Wrap)
            {
                  writer.AddAttribute(HtmlTextWriterAttribute.Wrap, "off");
            }
      }
      else
      {
            if (mode1 == TextBoxMode.SingleLine)
            {
                  writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
                  string text1 = this.Text;
                  if (text1.Length > 0)
                  {
                        writer.AddAttribute(HtmlTextWriterAttribute.Value, text1);
                  }
            }
            else if (mode1 == TextBoxMode.Password)
            {
                  writer.AddAttribute(HtmlTextWriterAttribute.Type, "password"); <------------------ notice lack of code to pass in the Text value
            }
            num1 = this.MaxLength;
            if (num1 > 0)
            {
                  writer.AddAttribute(HtmlTextWriterAttribute.Maxlength, num1.ToString(NumberFormatInfo.InvariantInfo));
            }
            num1 = this.Columns;
            if (num1 > 0)
            {
                  writer.AddAttribute(HtmlTextWriterAttribute.Size, num1.ToString(NumberFormatInfo.InvariantInfo));
            }
      }
      if (this.ReadOnly)
      {
            writer.AddAttribute(HtmlTextWriterAttribute.ReadOnly, "readonly");
      }
      if (this.AutoPostBack && (this.Page != null))
      {
            string text2 = this.Page.GetPostBackClientEvent(this, "");
            if (base.HasAttributes)
            {
                  string text3 = base.Attributes["onchange"];
                  if (text3 != null)
                  {
                        text2 = text3 + text2;
                        base.Attributes.Remove("onchange");
                  }
            }
            writer.AddAttribute(HtmlTextWriterAttribute.Onchange, text2);
            writer.AddAttribute("language", "javascript");
      }
      base.AddAttributesToRender(writer);
}
 
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
LVL 23

Expert Comment

by:b1xml2
ID: 13793841
for completeness, the code that populates the TextArea element (MultiLine)

protected override void Render(HtmlTextWriter writer)
{
      this.RenderBeginTag(writer);
      if (this.TextMode == TextBoxMode.MultiLine)
      {
            HttpUtility.HtmlEncode(this.Text, writer);
      }
      this.RenderEndTag(writer);
}
0
 
LVL 23

Expert Comment

by:b1xml2
ID: 13793859
so when the password type is rendered to the client, the text is never ever persisted. It's the code inside the control that makes this so.

HTH
0
 
LVL 5

Expert Comment

by:ovalsquare
ID: 13794228
Good explanations all. Only one thing to add however, is that no one has mentioned where the control's text/properties would be persisted. Namely, the page's ViewState, which for security considerations is good that by default it is not persisted on PostBack.

Ted
0
 

Author Comment

by:tparke
ID: 13794339
OK...bear with me while I ask a few stupid questions (I'm new to ASP.NET and C#).

First, what happens if I have a form where there are several fields on it, one of which is a textbox with TextMode set to Password.  If the user enters an encrypted password, then makes an error somewhere else with one of the other fields on the form, the postback will catch the error and draw the user's attention to the field that generated the error.  However, at the same time, even though there was no error in my password textbox field, it is cleared out, forcing the user to enter the encrypted password again!  Is this the behavior that is intended?  It looks like the only way that I can make the textbox value "stick" is to change the TextMode property to regular text.  There's no way around this?

Second,  b1xml2, I'm a little confused about the code that you included above.  What is it supposed to do?  Is this some way to restore the textbox password after the postback causes it to clear out?
0
 
LVL 23

Expert Comment

by:b1xml2
ID: 13794425
ovalsquare, the password is not persisted in ViewState.. This is a common misunderstanding...where the values are of FORM elements, these values are NOT kept in viewstate. This applies to TextBoxes. After a postback, the values inside the Request.Form collection is retrieved and set into the controls.
0
 
LVL 12

Expert Comment

by:laotzi2000
ID: 13794427
I think that's what most sites do.
If you try to register at some sites, if you fail for some reason, such as user name exists, normally
your password is cleared.
To solve that, you should do client side validation. When there is no postback, textbox will not
be cleared.
0
 
LVL 23

Expert Comment

by:b1xml2
ID: 13794454
tparke, it is a good idea to get the user to re-enter his password as it is not a good idea to persist the password manually through postbacks. plus his password becomes plain text when viewing the source code and defeats the point of hiding it by placing asterisks... think about it
0
 
LVL 23

Expert Comment

by:b1xml2
ID: 13794465
tparke, the code posted was retrieved thru Reflector and shows you where the text is not sent back across postbacks.....
0
 
LVL 23

Expert Comment

by:b1xml2
ID: 13794471
what loatzi says will not hold true for non-upstream browsers (by default non MSIE 5+ browsers) as there will be no client-side validation....
0
 

Author Comment

by:tparke
ID: 13795584
To b1xml2:  thanks for the advice, but there are two problems with that approach in our application.  The web form that I'm referring to is an enrollment-type of form, where the user specifies several different field values to open a new account.  Among them is the initial password that will be used to access the account once it is created.

First, our users will complain about having to re-enter the password field when they have made a mistake on another field on the enrollment form, because the password field will be cleared when the postback directs attention to the field that caused the error.

Second, the user may not notice, or will forget, to complete the password field again.  The password field is not required, so if it is blank, our system will assign a default password.  This means that, if the user forgets to complete the password field again as they correct the other errors, the system will default the password, the user is never the wiser, and the customer goes away thinking that their password is one thing when it is something else.

So unfortunately, the behavior of the password field (the way it clears out after a postback), will cause a problem for us.

I've been playing with it all day, and I think I have found a method that will work, as soon as I can get the bugs out of it.  I created a new textbox field with TextMode set to regular text, and hid it from view.  When the user clicks a button and submits the form, the first thing that I do is save the value of the encrypted password field in the hidden textbox (since it is regular text, it will not clear out after the postback).

When the form reloads after a postback discovers errors, I default the password field back to the contents of the hidden text field, thereby restoring the password field value as the page reloads.  This is about the only way I can figure to circumvent the password textbox behavior.
0
 
LVL 5

Expert Comment

by:ovalsquare
ID: 13795676
First, you should be using built-in validation controls for all required fields, make them dynamic, so they'll check on client-side before the user is able to cause a post-back. In case javascript is turned off etc, of course, make sure you run your submit events wrapped in a

If Page.IsValid Then

'Save record etc.

End If

That will deal with everything better for you (although in the case of javascript turned off, the user will still have to re-enter the password as there will be a postback).

If you still want to have it available in postback, no need in adding hidden fields etc., just add the password text into the ViewState (ViewState.Add("Password"), and then repopulate from that (which is essentially what you're doing with your hidden textbox way, except that at least it's not totally clear text html plus the textbox's text property in the ViewState, but in the ViewState only/directly).

Or just use a textbox without the password attribute ;-)

Ted
0
 

Author Comment

by:tparke
ID: 13796091
Thanks, Ted!  I like your suggested solution about using ViewState.  But...<sorry>...I'm new to ASP.NET and Visual C#, and I'm still trying to learn about all the different object models, properties, etc.  This question is the first I've heard of the ViewState item.

Could you describe to me in a little more detail about how I would use this solution?  In other words, right now, in the button_click event in my web form, the first thing that I'm doing is saving the value of my password field to my hidden textbox:

private void btnSubmit_Click(object sender, CommandEventArgs e)
{
    txtHiddenField.Text = txtPasswordField.Text;
    ....
}

Then, when my javascript function runs, I'm using document.GetElementById to obtain the value of the hidden textbox and transfer it into the password field.  So, if I'm understanding you, then I would change the event to something like this:

private void btnSubmit_Click(object sender, CommandEventArgs e)
{
    // **** STEP 1 ****
    // Some kind of "ViewState" statement would go here to save the
    // the value of the txtPasswordField control.
    ....
}

Next, in my javascript function that executes when the page is re-rendered:

<script language="javascript">
  function restorePasswordField()
  {
      // **** STEP 2 ****
      // Restore the value of the txtPasswordField control here from the ViewState.
  }
</script>

<body onload="restorePasswordField();">
  <form id="myPage">
    .....
  </form>
</body>

In the commented sections above, where I've noted STEP 1 and STEP 2, what code would go here to implement your suggestion using ViewState?
0
 
LVL 5

Expert Comment

by:ovalsquare
ID: 13796567
Skip the javascript and just do in the page load in C# (and forgive any minor C# syntax errors - quickly translated from vb.net):

private void Page_Load(Object sender, System.EventArgs e)
{
  if Page.IsPostBack {
     if ViewState.Item("Password") != null { textbox1.text = ViewState.Item("Password") }
  }
}

private void btnSubmit_Click(object sender, CommandEventArgs e)
{
    // **** STEP 1 ****
        ViewState.Add("Password", TextBox1.Text)
    ....
}

BTW, ViewState is where the properties etc of each item is stored for availability after PostBack (unless otherwise specified on the page level or per control). The encrypted string is what you'll see if you look at the source of a page under the ViewState element, particularly a page with many controls utilising ViewState (which they do by default). That's why you want to make sure that you specify what controls you actually want to utilise ViewState is there's no need as it just increases overhead (small price to pay if needed, but stupid if not). You should check out the viewstate of a big datagrid. More info, just do a google search or experts-exchange one on the viewstate.

Let me know if you need more explanation.

Ted
0
 
LVL 23

Expert Comment

by:b1xml2
ID: 13796823
tparke,

you should really think about the architecture and flow of the forms. The password should not be stored at any point in ViewState nor any where else. Now, since you say there are a number of fields that may fail validation, it would make a lot of sense if you were to have the passwords set after the fields have passed validation. Even as you look in Experts Exchange and other web applications be they intranet (esp in huge government departments) or commercial ones, no one ever persists the password across postbacks.

If there is a lesson to learn, it should be this: if other brands are being security conscious, shouldn't you be too? Now where would that leave you. You could expose all the non-password fields and when they are validated with the next button, they are rendered invisible and the password fields are made visible. It is at this point that when the next button is submitted, you get the user password. If you persist the password in any shape or form, then you run the risk of not enforcing a security conscious environment. What does your application know that other very successful ones do not?????

Please think this over. Code is as good as the idea behind it. If the idea turns out to be rotten, the code is rendered not only useless but potentially harmful.
0
 

Author Comment

by:tparke
ID: 13797907
b1xml2, thanks...good points all around.  In the context of a regular login page, the password field clearing out is not such a big deal.  But in our enrollment context, it presents a problem as I've noted above.

Your suggestion about making the process a two-step process (1. supply all enrollment information; commit, and 2) supply password, commit.) is not a bad idea, but it would mean we'd have to redesign our whole page as well as the work flow (not a task I'd look forward to doing...haha!).

Our application is internal to our company, so the main thing that we'd be protecting is prying eyes over the shoulder of the agent conducting the enrollment.  I really like the idea of storing the password in the ViewState, which I intend to try on Monday when I get back to work, but in order to make the process secure, why not encrypt the password before I store it?  That way, if a user views the source, they'd just get a garbled word.
0
 
LVL 5

Accepted Solution

by:
ovalsquare earned 200 total points
ID: 13808479
tparke,

I agree with b1xml2 regarding security, hence my first comment "the page's ViewState, which for security considerations is good that by default it is not persisted on PostBack." However, the ViewState, although still not secure, is better than your initial clear text suggestion.

If all that's holding you back is redesigning your pages, I would do it. However, one solution that would help minimize the need to change everything, is to simply put the password fields in a Panel set to invisible ("PasswordPanel"), and the rest of your form controls in another panel (EnrollmentPanel). Add a submission button to the EnrollmentPanel which would simply do this in your code-behind:

if Page.IsValid {
EnrollmentPanel.Visible = False
PasswordPanel.Visible = True
}

As long as you put CausesValidation = True for this button, then all your validation controls will fire ONLY for the controls in that panel. Thus, you won't get to the PasswordPanel until all other data is valid (via validation controls mentioned above). Then, once all data verified, your PasswordPanel is visible and voila, no need to deal with any your existing problems - all other data ready to go when you hit the PasswordPanel Submit button, at which point all properties of all the controls in all panels are available to actually do the final database insert etc. Panels are your friends!

Put your existing Submit button in the PasswordPanel which should work with minimal fuss as is. The only hickup would be if you do some database validation for some of the initial controls (i.e. verify that username does not already exist). No problem, just run a check on these in the EnrollmentPanel submit click event, and if good to go, PasswordPanel.Visible = True etc.

Ted
0
 
LVL 23

Assisted Solution

by:b1xml2
b1xml2 earned 100 total points
ID: 13808582
i agree with ovalsquare that half a loaf is better than none in that at least the data/password is obfuscated, not really encrypted as you can decipher any viewstate text so long as you have not set enableViewStateMac to True. If you wish to store it in the ViewState, then make sure you set this value on..
<%@ Page Language="VB" enableViewStateMac="True" %>
0
 

Author Comment

by:tparke
ID: 13810135
Thanks to both of you, ovalsquare and b1xml2, for your help and valuable assistance!  This method is working...I appreciate all your help!
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In .NET 2.0, Microsoft introduced the Web Site.  This was the default way to create a web Project in Visual Studio 2005.  In Visual Studio 2008, the Web Application has been restored as the default web Project in Visual Studio/.NET 3.x The Web Si…
IntroductionWhile developing web applications, a single page might contain many regions and each region might contain many number of controls with the capability to perform  postback. Many times you might need to perform some action on an ASP.NET po…
This Micro Tutorial will teach you how to add a cinematic look to any film or video out there. There are very few simple steps that you will follow to do so. This will be demonstrated using Adobe Premiere Pro CS6.
When cloud platforms entered the scene, users and companies jumped on board to take advantage of the many benefits, like the ability to work and connect with company information from various locations. What many didn't foresee was the increased risk…
Suggested Courses
Course of the Month21 days, 1 hour left to enroll

810 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question