Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Security

JavaScript Password Protection


WebReview.com: January 26, 2001: JavaScript Password Protection

At a Glance

Want a simple means of password protecting an area of your site? JavaScript—while not the best choice for high-security situations—is the perfect means of adding simple authentication. Here's a script that will help you do just that. Note: Optimized for IE and NN 6.0.

Working Demo: The password is set to "swordfish".

Code Files: Download in .zip format.

Protecting your Web site from prying eyes requires a server-side solution. With Kerberos authentication, users have their own usernames and passwords and access can be granted to a directory by adding the appropriate htaccess and htpassword files. But what do you do if your ISP doesn't support such means of password protection? JavaScript can offer a limited amount of protection for just about any site. By limited protection, I mean that someone who knows what they're doing can bypass the authentication simply by viewing the code in most cases. So, if you need to protect anything really important, like social security numbers, company trade secrets, or charge card information, a server-based solution is the only way. But, if you just want to keep the general public from viewing your Web site, JavaScript can be just the ticket.

There are a few scripts out there that are written for just this purpose, but most seem to have some type of drawback. Many will only protect one page at a time—the password for the page becomes the page's URL, and if you get it wrong, you get a "Page Not Found" error. You would have to give out a number of passwords if you wanted people to be able to navigate your site with such a system. Some scripts only protect at the home page and nowhere else, so if someone happens to surf to a subpage via a search engine, the protection has been completely bypassed. When a friend of mine asked me if there were some way of password protecting her club's Web site, I came up with a way that was a little more user-friendly and not quite so simple to defeat for the average amateur. Once you set up the "front door," adding password protection is as easy as pasting in a couple lines of code into the files you want to protect (see working demo—password is "swordfish").

Overview of the Strategy

Although it's easy to turn off JavaScript and search for the password by viewing the source, we can use a couple different techniques together to slow people down enough that they may just give up and go on. Please refer to the diagram below. When someone comes to the site via the front door (index.html in our case), we have a frameset.

Password Strategy
Password Strategy

The frameset will consist of two pages - one that holds the password (blank.html) and an interim page that stops the user until the password frame has loaded. If they don't have a JavaScript-enabled browser (or have JavaScript turned off for devious intentions), they will be redirected by the interim page to an Access Denied page (pw_required.html). If they do have JavaScript enabled, the password frame will automatically redirect the interim page to go to the site's real home page (homepage.html) where they will be asked for a password. If they supply the correct password in the prompt, they are given access and a cookie is set with the password so the user can move about freely within the site without having to reauthenticate on every page. If they supply an incorrect password, they will be dumped off to the Access Denied page. If someone tries to view the code by just loading one of the pages outside of frames, a line of JavaScript will again kick them out to the Access Denied page.

The Door Frame (index.html)

The entire password protected Web site will be presented through a frameset. Don't worry. Your site will function fine as is within the frameset. This will make it a little more difficult for the casual user to find the password. There will be two frames. The main frame initially contains 'stop.html', an interim page that stops the user until the site's password can be loaded, and 'blank.html', which contains the site's password. It is necessary to have the password loaded into the hidden frame first so the JavaScript on the password protected pages will have something to compare against. The site's real home page (homepage.html) will automatically load into the main frame after the password frame (blank.html) is loaded. The main frame is set to take up 100% of the screen. You won't even be able to see the frame that the password is contained within. Its portion of the screen is set to "*" (that is, whatever is left over, which is nothing since the first frame takes up 100%). Having the password contained in one place on the site makes it a snap to change the password should you ever wish to do so.

<head>
<title>Password Protected Site</title>
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
</head>
<frameset border=0 rows="100%,*">
<frame src="stop.html" name="body"><!---tab way over---> <frame src="blank.html"
name="blank" scrolling=no noresize>
</frameset>

Make sure you set the frames up with both frame source tags on one line and the closing frame tag on the very next line. And, instead of just typing the second frame source tag next to the first frame source, we're going to tab over—way over—so that if the source is viewed, they won't see the second frame source. It will be way off to the right and they'd have to scroll over to see it (should they think to do so). This will make it look initially like there's only one html page associated with the frames and they may not find "blank.html", which contains the password.

The Front Door (stop.html)

To weed out people who do not have JavaScript-enabled browsers (or those who've turned it off in an effort to bypass the system), we make an interim page (stop.html) that contains one line of script between the head tags:

<META HTTP-EQUIV="REFRESH" CONTENT="2; URL=pw_required.html">

We also put a title "Password Required" just to lay down the law. If the user has JavaScript enabled, they'll be sent automatically to the home page (to log in if necessary) when the other frame that contains the site's password is loaded. If they don't have JavaScript enabled, the Meta tag will time out after 2 seconds and send them to the "Access Denied" page.

Access Denied (pw_required.html)

The Access Denied page (pw_required.html) contains no special scripts. It should, however, contain links to the site administrator's email address in case there is a problem for an authorized user and a link (to homepage.html) that lets them try again if they didn't get it right the first time. It might be nice to snazz this page up with your site logo.

The Key Under the Mat (blank.html)

The blank frame will contain the file, "blank.html", where a JavaScript variable is set for the password. The variable is "pw" and its value (the actual password) is set to "swordfish" in this example. You may want to make it a little more confusing to prying eyes by naming the variable something other than "pw". If you do, however, make sure you change the variable in "lockit.js" also. You could also tab it over to the right as you did in the frames file to help hide it.

<script language="javascript">
var pw = "swordfish"; <!---tab this line way over to the right--->
if (parent.location.href==window.location.href) { 
        window.location.href="pw_required.html" 
        }
</script>

The "if" clause just below the password line makes it a bit harder to view the source of the file. It looks to see whether the page is being viewed in frames or not. If it's not being viewed in frames, it's assumed that the person may be trying to view the source and automatically kicks them out to the "Access Denied" page. This line of code will be included in "lockit.js" for all of the other pages you want to protect also. While it won't stop someone from turning JavaScript off to view the source, it's just another encumbrance to slow them down and make it more of a pain than it's worth.

Now that we've loaded the site's password, we can tell the main frame to load the site's home page. In the body tag of this file, we'll do a JavaScript onLoad event:

<body bgcolor="#ffffff" onLoad='javascript:parent.body.location.href="homepage.html"'>

The Bouncer at the Door (lockit.js)

In your home page and in every other page you want to include in the password protected area, you need to put the following lines of code in between the header tags:

<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
<script language="javascript" src="lockit.js"></script>

The first line, the Meta tag, is used to tell search engines not to index the Web page. This should help prevent people from stumbling onto your site when they're surfing. If someone does happen to find the site via a subpage, the JavaScript will either kick them out to the Access Denied page because they are not viewing the page within the site's frames, or it will ask for authentication when it sees there is no cookie containing the password. The second line will call in the JavaScript file that does all the dirty work. Don't put it in any of the "front door" pages we just discussed—only in your Web site pages. Be sure to keep "lockit.js" in the same directory as your site pages or adjust the path to it accordingly on each page.

Now let's take a line by line look at just what's in the code of "lockit.js". Note that the numbers at the beginning of each line below are only there for reference and should not be included in the final code.

<a name="1"></a>1.      function setCookie(name, value) {
2.        var newCookie = name + "=" + escape(value);
3.         document.cookie = newCookie;
4.       }
5. 
<a name="6"></a>6.       function getCookie(name) {
7.         var theCookie = document.cookie;
8.         var prefix = name + "=";
9.         var begin = theCookie.indexOf("; " + prefix);
10.         if (begin == -1) {
11.           begin = theCookie.indexOf(prefix);
12.           if (begin != 0) return null;
13.         } else
14.           begin += 2;
15.         var end = document.cookie.indexOf(";", begin);
16.         if (end == -1)
17.           end = theCookie.length;
18.         return unescape(theCookie.substring(begin + prefix.length, end));
19.       }
20.
<a name="21"></a>21.    if (parent.location.href==window.location.href) {       
22.             window.location.href="pw_required.html" 
23.     }
24.
<a name="25"></a>25.    var pw = getCookie("mySite");
26.
<a name="27"></a>27.    if (pw != parent.blank.pw) {
28.             askPW();
29.     }
30.
<a name="31"></a>31.    function askPW() {
32.             var password = prompt('Please enter your password:');
33.             if (password == parent.blank.pw) {
34.                     setCookie("mySite",password);
35.             document.location.href="homepage.html";  
36.             } else {  
37.                     document.location.href="pw_required.html"; 
38.             }               
39.     }

Lines 1-5 encompass a JavaScript function that sets the cookie when someone gets the password right. A cookie is used to avoid having to log in again for each password protected page.

Lines 6-19 encompass a function that retrieves the cookie.

Lines 21-23 look to see if the page is being viewed in frames or not. If it's in frames, its "parent" will be "frames.html". If not, its parent will be itself. If that's the case, we can surmise that someone wants to attempt to view the source and bounce them out to the Access Denied page.

Line 25 sets a variable called "pw" to the value it gets from the cookie (if it's there). Don't get this confused with the "pw" you set in "blank.html". Change only the one in "blank.html".

Lines 27-29 compare what was gotten from the cookie to the real password set in the blank frame. If it doesn't match or is not found, we need to ask them for their password.

Lines 31-39 encompass a JavaScript function that asks for the password (line 32), then compares what they enter into the text field with the real password in the blank frame (line 33). If it matches, it will set a cookie on their machine (line 34), and load the home page (line 35). If the password doesn't match, they are kicked out to the Access Denied page (line 37).

In Conclusion

In a nutshell, to employ this password strategy, we need to do the following:

  1. Rename your default home page to "homepage.html".
  2. Add the new pages "index.html", "stop.html", "pw_required.html", "blank.html", and "lockit.js" to your site. You may download all five files from a zipped file here.
  3. Include the lines of code that call the text file "lockit.js" and the "no robots" Meta tag in the head tags of each page you wish to protect.
  4. Set the password value for the variable "pw" in "blank.html" to whatever you wish and give the password to authorized users, instructing that they need to have JavaScript and cookies enabled in their browsers.

While a JavaScript password scheme is not the answer for sites where security is of utmost importance, it can be useful for sites where a lesser degree of protection is acceptable—and it can be simple to use. Once the five "front door" files are set up, password protection is as easy as cutting and pasting two lines of code. Good luck with your site.


Pat has been developing for the Web since 1995. He was an instructional technologist for Penn State's World Campus online learning initiative and is now developing Web applications and simulations for SMGnet of State College, PA.



Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.