Better Passwords #1: The Masked Password Field

Password fields.

We all have to deal them, but they’re never a joy to use. Clearly they have to be obfuscated in some way–to keep our passwords safe from bypassers’ prying eyes–but when you’re unable to see what you’re typing, it’s easy to become hesitant, nervous even, and unsure of whether you’re entering the right information.

I’m an experienced typist, but I still type passwords with one finger! And some forms even ask you to enter them twice, just to be sure that you know what you entered, and that you entered it correctly.

Password fields are annoying. There has to be a better way.

Platform Solutions

Away from the Web, various platform solutions have been presented. Mac OS wireless-password fields have a “Show password” checkbox next to them, which allow you to view it in plain text; we’ll be looking at that solution for the next post in this series.

In this post we’re going to look at a solution more common among handheld devices. Recent Symbian and Android devices do this, but it’s arguably more commonly known on the iPhone and iPod touch.

The Masked Password Field

A masked password field obscures all the characters except the last one, which is visible as plain text. So you can always see what you’re typing, but the whole password is never revealed, making it near-impossible to read surreptitiously:


A login form with a masked password field.

I’m now going to show you a script that adds this behavior to ordinary "password" fields.

The script is quite complex. The core of what it does is simple, but there are several browser-related and usability gotchas to consider, and these add some complications. So while I’ll try to give you a good sense of how it all works, this is less a how to post, and more a whether to overview. The real nitty-gritty is in the script itself, which is extensively commented with details of what does what, and why.

Have a look at the demo and grab the script. It works in all modern browsers, including IE6:

First: the Markup

To begin with, we need a "password" type field. We have to do this as a progressive enhancement, so that unsupported or no-script browsers still have a proper password field:

<label for="pword">Password:</label>
<input type="password" id="pword" name="pword" />

The script will convert this to a "text" field, as well as creating a second, "hidden" field. The hidden field is where we’ll store the plain, unencrypted version of the password, while the visible field is what users type into, and where the masked password is shown.

So this is what the markup will ultimately become:

<label for="pword">Password:</label>
<span>
   <input type="hidden" name="pword" />
   <input type="text" class="masked" id="pword" autocomplete="off" />
</span>

You can see how only the hidden field retains the name attribute, so that it’s the only one to be submitted. The visible field is what users see, but its value would be junk to any other process, so we stop it from being submitted, and (crucially) don’t allow autocomplete to remember it either (because all it would remember is a series of dots, with no way of decoding them).

Originally, I had an elegant process for doing this markup conversion, but naturally enough it failed to work in IE. In Internet Explorer, even the latest version, you’re unable to modify the "type" attribute of a password field, or set the "type" of any form field that was generated in the DOM. The only way to create form fields in IE is to write them out in source text and inject it into the page with innerHTML! It’s ugly, I know, but it’s what it takes to make this work.

Then: the Events

Once we have the markup, we need to handle its events; we have to be able to respond to any kind of input, whether it’s by keyboard, mouse, or some programmatic means. There are so many ways, in fact, that it would be impossible to cater for them all in advance; but we can catch the changes retrospectively, and modify the value just after it’s been input. As long as we do it fast enough, users should be unable to notice the difference. To achieve this the script uses four event-listeners.

The first two provide a solid foundation, being the most robust and cross-browser compatible; these are: onkeyup to catch primary keyboard input, and onchange to catch secondary input such as pasting from the mouse.

Then we supplement them with some nonstandard events that are similar to onchange, but which respond immediately instead of waiting for the field to lose focus; these are: oninput (which works in the latest builds of the top browsers apart from IE), and onpropertychange (which is IE-only). We have to be careful with these events, though, because they also fire instantly from programmatic input; we therefore must watch that our code doesn’t create an infinite loop, by causing an event that it also responds to.

So with that spread of event listeners, we’ve covered every base and can respond to user input by any method, virtually instantly in most cases. And when we do respond, that’s when the masking happens.

When new input arrives in the text field, the first task is to extrapolate the entire plain password from the data we already have, plus the new input. For example, if the hidden field contains the value "passw" and the text field now has the value "●●●●wo", we can extrapolate–by counting letter by letter, from the first–that the new value is "passwo". Once we have that, we encode the whole value and write it back to the visible field so that it now says "●●●●●o", at the same time as updating the hidden field with the plain version, "passwo". (The dots themselves are a unicode character, 25CF, which is what most browsers use for regular password fields.)

This is a repeating, reciprocal process: new input triggers decoding, which triggers re-encoding, and by this process we continually have both a masked and a plain version of the password; the form can be submitted at any time, and the hidden field will always reflect the masked value you can see.

Now for the Gotchas!

As we’ve just seen, encoding and decoding of the masked password happens by comparing two values character by character, but we can’t do that unless we know which character equates to which; for example, the dot at index [0] corresponds with the letter at the same index. Ultimately, we can’t allow users to input characters at the beginning or middle of the password because that would break the equation; it’s only when input is limited to the end that we can know how the characters equate.

To implement this we have to limit the caret position, so the script has a routine which does precisely that–whenever the field has focus, it continually forces the caret to be at the end–so you can edit or select from the end, but not from the beginning or middle.

We’ll also encounter some security issues with regard to how browsers treat the value contained in the field. Since the field we’re working with is just a "text" field, browsers give it no special consideration. With real "password" fields, there are limits placed on how values carry over; for example, user input into a password field is not retained after soft refresh, or when coming back in the history; but with ordinary text fields, it is (or may be).

So we have to implement additional behaviors to take control of this. The script will delete any default value from the original field, and also trigger a reset() event to remove any residual input after soft refresh. (You’ll also remember how we had to disable autocomplete on the field, because the value the browser would try to remember is just a bunch of dots.)

All things considered then, this implementation is far from straightforward. Like I said at the start–the core of it is simple, but the devil, as always, is in the detail.

Conclusion

A JavaScript solution for this is probably impossible to implement without any side effects. The browser is set up to deal with "text" fields at a lower level of security than "password" fields, and this difference is why extra hacks were needed to bring the masked field up to the same level. But more fundamentally, we need to break the physical link between the data in the visible field and its counterpart in the hidden field in order to remove the input restrictions, and that really requires a lower-level implementation (for example, being able to store data as properties of an individual character).

I think this kind of password field is a good idea, but browsers should be implementing it as an input type in its own right.

Win an Annual Membership to Learnable,

SitePoint's Learning Platform

  • fattyjules

    Like the previous poster, I’m not convinced password masking stops anyone shoulder surfing anyway, unless you can type quickly.

    A better solution is the ‘show password’ checkbox. You get total secrecy by default, or total disclosure if you need it. I’d like to see this as something browsers handle natively. Imagine no more ‘confirm password’ boxes! Sigh…

    • Ahmad Alfy

      This has been introduced on A List Apart
      I think this is the best solution

  • http://logicearth.wordpress.com logic_earth

    I put a toggle on mine, on and password is show plain, off it is masked. 90% of the time when I am entering passwords there isn’t a chance of people behind me. So in reality the masked password field provides no benefit for me.

  • http://logicearth.wordpress.com logic_earth

    I forgot to mention…for all that is holy…do not use autocomplete off! I would much prefer my password manager to work…

  • http://www.brothercake.com/ brothercake

    It’s just not possible to implement this script without disabling autocomplete – it’s an either/or deal – because all autocomplete would remember is “********” (ie. the dots, with no idea what they mean). I’m sure you don’t want your password manager to remember useless junk – remembering nothing is better than that, which is why autocomplete is disabled. Perhaps that makes the whole idea untenable; yeah, perhaps.

    As to whether this kind of field truly protects against shoulder snoopers, I agree that it’s debatable. It’s certainly not as good as a normal field in that respect. Perhaps this kind of field only belongs on mobile devices, where that’s not an issue.

    But I’m just throwing ideas around to see if any will stick :) Stay tuned for #2 in a couple of days.

  • prafuitu

    Symbian is doing this since …forever! And that’s way before the first iPhone was out! :P
    Also, the reason for this is that on regular mobile devices you don’t have a qwerty keyboard, just a T9 (text on 9 keys) keyboard and the user needs to know which is the current letter…

    People should stop giving so much credit to Apple for “reinventing” the mobile devices, because they just copied what others were already doing and dressed it in prettier clothes.

  • Allan Mullan

    Not sure if this would improve much but instead of doing timers to move the caret to the end would it not be easier/better to listen for mouse events?

  • http://www.optimalworks.net/ Craig Buckler

    Interesting idea and I agree it’s something which browser vendors could easily implement.

    Unfortunately, there’s another subtle problem with a JavaScript solution: the hidden ‘pword’ field can be examined in the DOM to reveal the user’s password. That can’t be done with a standard password input.

    Therefore, you could use Firebug at a user’s PC if they wandered off after entering their password. It would also be susceptible to XSS attacks. Finally, it’d also be easy to host the login page in a frame and read the password field.

  • noonnope

    this feat is more useful in a game. in real life, only good if in front of an atm.

  • Problems

    Protect your Usernames and passwords.

    The problem is that users need so many Passswords that they must write them down. Or store them in some way. This makes them insecure.

    Protect your Usernames and passwords.
    http://www.acomputerportal.com/protect_your_password.html

  • Jacque Harper

    Here’s a completely different take on this question. Jakob Nielsen argues, and I’m inclined to agree:
    “It’s time to show most passwords in clear text as users type them. Providing feedback and visualizing the system’s status have always been among the most basic usability principles. Showing undifferentiated bullets while users enter complex codes definitely fails to comply.
    “Most websites (and many other applications) mask passwords as users type them, and thereby theoretically prevent miscreants from looking over users’ shoulders. Of course, a truly skilled criminal can simply look at the keyboard and note which keys are being pressed. So, password masking doesn’t even protect fully against snoopers.
    “More importantly, there’s usually nobody looking over your shoulder when you log in to a website. It’s just you, sitting all alone in your office, suffering reduced usability to protect against a non-issue. ”
    The complete text of his article can be found here:
    http://www.useit.com/alertbox/passwords.html

  • Justen

    It’s definitely an interesting solution but for numerous reasons explained in the article and comments I can’t consider it “mature” enough for real-world use – especially considering the utility gain vs. a “show password” toggle box.

    There *are* some tricks out there on the web for determining cursor position that may solve one problem, but the password manager breakage is a big no-no for me.

    • http://www.brothercake.com/ brothercake

      Believe me – I spent a loooong time looking for a way not to do that, and i’m 99.5% sure that it’s not possible in a cross-browser way. There are solutions for finding the caret position, but a) they don’t work for created elements in IE, and b) it’s not enough anyway.

      There are other scripts around that do this, and they all have the same issue (or they ignore it and have the root issue that it prevents).

      I largely agree with the detractors – I don’t think it’s a good and workable solution for the problem. But the cursor position issue is not why :)

  • Andrew

    I would never sign up for a site that is using this script. Why? I can’t navigate through the password. I use the home and arrow keys to hash together unique keywords to create a very difficult password (but easy to hash together again, if the algorithm is known).

  • BrenFM

    Personally I think the whole idea of password masking is brilliant and simple and I can’t understand why anybody would have trouble typing their password in.

    I have a pretty small set of passwords that I find easy to remember (and couldn’t be readily guessed by others) that I can type without even thinking about it. If I’m looking for more complex passwords (like those on all the WordPress sites I build for clients) then I use a password manager (Roboform).

    I just don’t see why it’s such a drama that passwords are hidden.

  • Jamie K

    Would be nice if this script hid the last character after a period of inactivity (couple seconds would be nice)
    Also would be nice if the backspace character didn’t reveal characters also

  • Tony Lezard

    For me it’s quite simple. I don’t want any character of any password I use appearing on the screen UNDER ANY CIRCUMSTANCES. If you need to see what character you just typed, look at the keyboard.

    Even the practice of displaying *s or U+25CFs is usually unnecessary.

  • Spha

    Passwords have been an issue to non computer literate people even still today it happens but i disagree with the masked password i think passwords are fine the way most website’s and application have them in most cases you don’t have anyone over your shoulders anyway so to me it seems irrelevant