Thursday, April 18, 2013

JavaScript: Password Validation using regular expressions and HTML5

. Guidelines for Secure Password Input

Use the "password" input type

Instead of <input type="text"> you should always use <input type="password"> as this lets the browser (and the user) know that the contents of that field need to be secured. Your password won't appear on the screen as you type and most browsers also won't 'remember' the values entered in password fields as they do with other form elements.

Confirm password input

Because the password input type obscures the text typed, you should let the user confirm that they haven't made a mistake. The simplest way to do this is to have the password entered twice, and then check that they are identical.
Another method is to display what they've entered as part of a 'confirmation page'. The problem here is that you're making the password visible in the browser, browser cache, proxy, etc. For security a password should never be displayed in HTML or even sent by email.

Enforce 'strong' passwords

If you're concerned about security you should have some policy on what constitutes a valid password. Some common restrictions are:
  • at least n characters
  • combination of upper- and lower-case characters
  • one or more digits
  • not related to other user data (name, address, username, ...)
  • not a dictionary word
Leaving the last requirement for now, as it requires a server-side script, let's see what's possible using just client-side HTML and JavaScript.

Server security

While having a strong password is a good first step, it needs to be backed up by additional measures on the server that prevent brute-force attacks. One popular approach is to install Fail2Ban to monitor log files and lock out repeat offendors. Of course that only works if your login system reports failed login attempts to a system log file. Otherwise your application needs to provide this function.

2. Basic Demonstration

The form below has three input fields: username, pwd1 and pwd2. When the form is submitted the checkForm script parses the input values and returns either true or false. If a false value is returned then the form submission is cancelled.
This code will work for browsers as far back as Netscape 4 (circa 1997).
Change Password
The code behind the form is as follows. If you're not sure how to place this on your page, you might need to read the preceding article on Form Validation, or view the HTML source of this page.
<script type="text/javascript"> function checkForm(form) { if(form.username.value == "") { alert("Error: Username cannot be blank!"); form.username.focus(); return false; } re = /^\w+$/; if(!re.test(form.username.value)) { alert("Error: Username must contain only letters, numbers and underscores!"); form.username.focus(); return false; } if(form.pwd1.value != "" && form.pwd1.value == form.pwd2.value) { if(form.pwd1.value.length < 6) { alert("Error: Password must contain at least six characters!"); form.pwd1.focus(); return false; } if(form.pwd1.value == form.username.value) { alert("Error: Password must be different from Username!"); form.pwd1.focus(); return false; } re = /[0-9]/; if(!re.test(form.pwd1.value)) { alert("Error: password must contain at least one number (0-9)!"); form.pwd1.focus(); return false; } re = /[a-z]/; if(!re.test(form.pwd1.value)) { alert("Error: password must contain at least one lowercase letter (a-z)!"); form.pwd1.focus(); return false; } re = /[A-Z]/; if(!re.test(form.pwd1.value)) { alert("Error: password must contain at least one uppercase letter (A-Z)!"); form.pwd1.focus(); return false; } } else { alert("Error: Please check that you've entered and confirmed your password!"); form.pwd1.focus(); return false; } alert("You entered a valid password: " + form.pwd1.value); return true; } </script>
expand code box
Remember that, as JavaScript isn't available in all browsers, you should user server-side scripting to validate all data before recording it in a database or text file. You might also want to spice up your forms using HTML5 Form Validation as we've done further down the page.

3. Advanced regular expressions

In the latest browsers - those that support JavaScript 1.5 (Firefox, Netscape 6/7, Mozilla, Safari and Opera 7) - you can use more powerful regular expressions. Older browsers will not recognise these patterns so the following is mostly useful for intranet rather than Internet applications.
The code presented above is fine in that it checks everything that we wanted to check, but uses a lot of code to test each requirement individually and present different error messages. We're going to show you now how to apply the password tests using a single regular expression.
Consider the following:
<script type="text/javascript"> // at least one number, one lowercase and one uppercase letter // at least six characters var re = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}/; var validPassword = re.test(input); </script> The type of expression used here is called a 'look-ahead' which tries to match the contained regexp against the 'future' part of the string.
Translation:
  • matches a string of six or more characters;
  • that contains at least one digit (\d is shorthand for [0-9]);
  • at least one uppercase character; and
  • at least one lowercase character:
inputresult of testreason
abcABCfalseno numbers
abc123falseno uppercase characters
abAB1falsetoo short
abAB12true-
Aa123456true-
If you are using a supported browser you can use the form below to test the regular expression:
Password Regexp Test
(input must contain at least one digit/lowercase/uppercase letter and be at least six characters long)
If you want to restrict the password to ONLY letters and numbers (no spaces or other characters) then only a slight change is required. Instead of using . (the wildcard) we use \w:
<script type="text/javascript"> // at least one number, one lowercase and one uppercase letter // at least six characters that are letters, numbers or the underscore var re = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])\w{6,}$/; var validPassword = re.test(input); </script> The \w is shorthand for 'any letter, number or the underscore character'.
Again, you can use the form below to test this regular expression:
Password Regexp Test 2
(as above, but this time ONLY letters and numbers are allowed)

4. Sample HTML and JavaScript code

You might implement this code on your own website as follows:
<script type="text/javascript"> function checkPassword(str) { var re = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])\w{6,}$/; return re.test(str); } function checkForm(form) { if(form.username.value == "") { alert("Error: Username cannot be blank!"); form.username.focus(); return false; } re = /^\w+$/; if(!re.test(form.username.value)) { alert("Error: Username must contain only letters, numbers and underscores!"); form.username.focus(); return false; } if(form.pwd1.value != "" && form.pwd1.value == form.pwd2.value) { if(!checkPassword(form.pwd1.value)) { alert("The password you have entered is not valid!"); form.pwd1.focus(); return false; } } else { alert("Error: Please check that you've entered and confirmed your password!"); form.pwd1.focus(); return false; } return true; } </script> <form method="POST" action="form-handler.php" onsubmit="return checkForm(this);"> <p>Username: <input type="text" name="username"></p> <p>Password: <input type="password" name="pwd1"></p> <p>Confirm Password: <input type="password" name="pwd2"></p> <p><input type="submit"></p> </form> As you can see, it's well worth learning the intricacies of regular expressions. They can be used not just in JavaScript, but also PHP, Perl, Java and many other languages. Some text editors (not just vi) also allow them when searching for or replacing text.

5. HTML5 Form Validation

We earlier mentioned HTML5 form validation. This is a new technique available in modern browsers and definitely the way of the future. A few simple form attributes can have the same effect as reams of JavaScript code libraries.
Here we have an enhanced version of the above code where we've added HTML5 required and pattern elements to apply regular expression tests within the form itself in supporting browsers. Helpfully the regular expression syntax is identical with just the /^ and $/ removed.
We've also added a tricky little onchange handler to the first password field which updates the pattern required by the second password field - in effect forcing them to be identical:
Change Password
Here you can see a screen shot from Safari of the form being completed. The red/green markers have been implemented using CSS:
In this example it should be clear to the user that the form can only be submitted once all three green ticks appear. In any case browsers such as Firefox and Opera will enforce the HTML5 validation rules and present messages as shown here:
Presumably the browser messages will change according to the users language - something that would never be possible using only JavaScript.
All we have changed from the previous example is to add some extra attributes to the form input fields. The rest of the HTML and JavaScript remains unaltered:
... <p>Username: <input type="text" required pattern="\w+" name="username"></p> <p>Password: <input type="password" required pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z])\w{6,}" name="pwd1" onchange="form.pwd2.pattern = this.value;"></p> <p>Confirm Password: <input type="password" required pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z])\w{6,}" name="pwd2"></p> ... The best thing about HTML5 attributes is that they have no effect whatsoever on unsupported browsers, so Internet Explorer will act as if they are not present and simply run the JavaScript as before.
At this stage both Firefox and Opera enforce HTML5 validation attributes in the browser while Safari only lets you use them in combination with CSS effects.

6. Customised HTML5 browser alerts

As you can see from the screenshot above the alert message in Firefox for when the input doesn't match the pattern attribute is simply "Please match the requested format.". Not entirely helpful in this case where we have a number of different requirements.
Fortunately it is possible to customise this message using just a touch of JavaScript.
Change Password
The only change between this and the previous example is that we've modified the onchange handler for the Password input and added one for Confirm Password:
... <p>Password: <input type="password" required pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z])\w{6,}" name="pwd1" onchange=" this.setCustomValidity(this.validity.patternMismatch ? 'Password must contain at least 6 characters, including UPPER/lowercase and numbers' : ''); if(this.checkValidity()) form.pwd2.pattern = this.value; "></p> <p>Confirm Password: <input type="password" required pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z])\w{6,}" name="pwd2" onchange=" this.setCustomValidity(this.validity.patternMismatch ? 'Please enter the same Password as above' : ''); "></p> ... When the Password input is changed we check its validity.patternMismatch flag to see whether it matches the pattern attribute. If it doesn't match we set a custom error message to appear when the form is submitted.
Whenever setCustomValidity() has been used to set a custom message the field in question will be regarded as invalid and prevent the form from submitting (at least in Firefox and Opera). To reverse this it needs to be set to blank, which we do when the input matches our regex rules.
The custom message we have set appears in Firefox as shown here:
You can see from the code that we have applied a similar technique to the Confirm Password field so it will now display "Please enter the same Password as above" if there is a mismatch between the two fields. Basically what we've achieved here is to replicate our JavaScript validation script using HTML5.
Because we are only checking for patternMismatch we are not affecting the other default validation options - namely the required attribute - so submitting the form with blank fields will still display the generic "Please fill out this field" alert message. To override those errors you would need to check the validity.valueMissing flag.

7. Conclusions

As you can see there's a lot involved in providing a rich user experience even for something as simple as changing a password. To summarise what we've covered:
  • Always start by emailing new users a random password or unique activation link;
  • Use the password input type to prevent passwords appearing on screen;
  • Decide what constitutes a 'strong' password for your system and enforce it:
    • server-side for spambots and users with JavaScript disabled;
    • using JavaScript for browsers that don't support HTML5 validation;
    • using HTML5 for a more user-friendly experience;
  • Use CSS rules to highlight valid/invalid input for browsers that don't have alerts built-in; and
  • Customise the HTML5 error messages where appropriate for improved usability;
Most of all don't feel you have to install massive JavaScript or jQuery libraries just to validate a form. By taking advantage of new browser standards as show in this article you can save time and resources and at the same time provide a better user experience.

7 comments:

Anonymous said...

They can be used in numerous ways to assist your young
puppy in learning where the proper place to go to the bathroom
is. But despite this, early training will need to
start just the same so that the dog will at least know what is expected of it.

Creating a social environment means puppy proofing the home, setting up boundaries and rules
and supervising, training, and providing exercise and mental stimulation.
Be sure to have the puppy sit when another dog is approaching.
Puppies need to see you keeping them safe while developing confidence with big dogs, little dogs, medium dogs and
different hair types and statures.

Feel free to surf to my homepage englishbulldogpuppies.us

Anonymous said...

Ӏ used to be reсommended this wеb site via
mу couѕіn. I am no longer certain whetheг
this submit is writtеn by mеans of him
as noboԁу else understаnd such
designatеd about mу difficulty.

You're incredible! Thanks!

Take a look at my website green carpet cleaning phoenix

Anonymous said...

Hoωdy! This is my 1st comment herе so I јust ωanted to
giѵе a quick shout out and tеll yоu I really enjoy
гeading through youг blog posts. Can you
recοmmend any othеr blοgs/websites/forums thаt сover the same tοpics?
Aрpreciаte it!

Here іs my sitе :: 3d dragon tattoos

Anonymous said...

I know this if off tοpic but I'm looking into starting my own weblog and was wondering what all is needed to get set up? I'm aѕѕuming having а blog like
yourѕ wοuld cost a ргetty pennу?
I'm not very internet savvy so I'm not 100% сertain.

Any гecommendations οг аdvice woulԁ be gгeаtly aрρrеciated.
Chееrs

My page; http://social.zarya-chern.ru/blogs/12807/26267/carpets-and-rugs-cleaning-servic

Anonymous said...

This page definitely has all of the info I wanted about this subject and didn't know who to ask.

My web site; seo training free

Anonymous said...

Hey there! I've been reading your site for a long time now and finally got the bravery to go ahead and give you a shout out from Atascocita Texas! Just wanted to say keep up the great job!

Here is my website learn about seo

Anonymous said...

The symptoms become evident after dog obedience training or play sessions.
Visit to observe the full illustrated article with links to resource articles in
the ASPCA like “How to Poison Proof your Home". The first layer with the covering which can be close to your body's close-knit and soft. These dogs have no feathering as within the long coated GSD's. He is educated to detect the venue of bedbugs in infested places.

Feel free to visit my webpage :: Breeder of Sable or Black and Gold German Shepherds