Script-based security

Privacy restrictions in a browser are at the user's discretion. If you want the restrictions lowered for your script, you have to convince the user, and provide systematic support so that it happens smoothly. Technically this is achieved by signing the script, and by embedding the script in a compatible web page to be viewed by a compatible browser. Netscape and Microsoft browsers have different systems for handling signed programs, but both are based on the same concepts. Netscape calls it object signing, Microsoft Authenticode. These systems are more commonly used for signing other downloadable and executable items such as plugins, ActiveX controls, and Java applets, but it is client-side JavaScript that is of interest here.

Microsoft's signing system cannot be used to directly sign JavaScript scripts. Only Netscape 4.0 supports a full signing system for JavaScript. Internet Explorer 4.0 Scriptlet functionality can control how scripts are used to a degree, but it is not a complete or robust security solution.

Signing of scripts has to be done in a manner that prevents tampering, or else there is no value in it. This means using some kind of secret code. Computer encryption and cryptography provide such codes. These subjects are very complex, so the details are only touched on here. For a thorough discussion, see this site http://www.rsa.com/rsalabs/newfaq/home.html.

In summary, the steps for signed JavaScript are:

Using HTML tags to support security

Chapter 2 covers basic use of the <SCRIPT> tag with LANGUAGE and SRC attributes and the <OBJECT> tag. That is enough for plain in-line JavaScript, but not for signed scripts. There are three problems from the HTML perspective:

The Netscape approach is to provide a general mechanism that works with all client-side JavaScript. Solutions for the three problems above are explained in turn.

Telling signed and unsigned scripts apart

Netscape signed and unsigned scripts are distinguished with a new type of file. This type could be specific to JavaScript, but instead a general format that works with all files is used. This is called a JAR archive, invented by Sun Microsystems. One such archive can contain many files. The <SCRIPT> tag has an ARCHIVE attribute which specifies the archive name. The SRC attribute is still required to identify the specific JavaScript file. An example:

<SCRIPT ARCHIVE="stock_updates.jar" SRC="ticker.js"></SCRIPT>

This way, the signing information is attached to the archive and the actual JavaScript source is the same as always. Assembling a JAR archive is part of the signing process and is discussed later.

For inline JavaScript that is embedded in an HTML file, signed <SCRIPT> tags can be identified by the use of an ID attribute, plus an ARCHIVE attribute either in that tag or in an earlier tag:

<SCRIPT ARCHIVE="misc.jar" ID=1> var first = 1; </SCRIPT>
<SCRIPT ID=2> var second = 2; </SCRIPT>

Keeping signed and unsigned scripts from interacting

Keeping signed and unsigned scripts separate is simple. Normally inline JavaScript and event handlers share all the JavaScript data in the page. Nothing stops one piece of script from using any of the data, such as form elements or other JavaScript functions, even if it comes from a signed script. So the rule is: "all signed or none signed". This way the page is entirely secure or entirely insecure. If you miss adding one ID to piece of script in a page, then the security is blown for all the pieces of script.

You can make it more complex than this simple rules if you wish: see http://developer.netscape.com/library/documentation/communicator/jssec/index.htm.

Preventing signed scripts from being changed

The problem of preventing changes to scripts is complex. Suppose an HTML page has three secure inline blocks of JavaScript specified via three <SCRIPT> tags. What stops someone saving the document to disk, modifying it and then presenting it to others as a "safe" script? Inline scripts are open to abuse since they are delivered exposed to the user with the rest of the HTML. The solution is extra, separate checking of the document.

This extra checking uses the HTML ID attribute. This attribute is a way of identifying a particular occurrence of an HTML tag. So an ID can be used to identify every inline script and every tag with event handlers in a page. There is a Netscape rule that says: every signed HTML page containing inline scripts must have at least one JAR archive, even if there is no SRC attribute. This creates a place to put data for the extra, separate checks. Every script piece, including handlers, must have a separate ID value, except for <SCRIPT> tags with SRC, since that SRC file is in the JAR archive anyway.

The extra checks take the form of a checksum or hash value for each piece of script. When the HTML page loads, the script pieces are picked out and hashed, and the new hash value compared with the one in the JAR archive matching the ID of that script piece. A match means all is well. A non-match means the page has been interfered with—a security breach. This arrangement means the HTML document can be loaded via a normal URL whether it's signed or not. If a security breach is detected, the document will be treated as an unsigned script.

The upshot of all this is that the HTML document must be separately processed once by its author so the JAR archive can be filled with the hash values. This is called page signing. JavaScript URLs and JavaScript entities can't be signed, and therefore can't be used in the normal way in HTML. They can still be written out via a document.write() inside a <SCRIPT> tag.

<HTML><BODY>
<SCRIPT ARCHIVE="special.jar" ID="1">
   document.write('first script piece');
</SCRIPT>
<SCRIPT ID="2">
   document.write('second script piece');
   document.write('<A HREF="JavaScript:alert(\'still piece two\')">Click me</A>');
</SCRIPT>
<FORM>
<INPUT TYPE="button" VALUE="Click me" ID="3" ONCLICK="alert('piece three');">
</FORM></BODY></HTML>

Why would Netscape encourage an approach that requires extra administrative tag attributes when writing HTML pages? One reason might be that this system allows several different web sites to contribute to the one HTML page in a mutually trustworthy way. That means several different companies can have their Web services connected together into one integrated package. That in turn might be the beginning of integrated and public inter-company software applications.

Writing Secure Scripts

Marking inline JavaScript with special HTML attributes is only half the content of signed scripts. The script logic itself must be created as well. Special features beyond plain JavaScript's capabilities must be required in the script or else there's no point signing anything

There are two sources of special features: JavaScript itself, and Java.

Within JavaScript, the available features are identified in the Reference Section. Outside of signed scripts, these features do nothing. Example features are:

Via ActiveX or LiveConnect, Java is the main mechanism that signed JavaScript uses for special features. Chapter 8 on Java and Applets describes how JavaScript can generally exploit Java. Plain Java is restricted to a harmless subset of the Java functionality, just as plain JavaScript is restricted to harmless control of the browser. Signed scripts (or signed applets) can gain access to the rest of the Java functionality.. Writing to local files and connecting to an arbitrary computer over the Internet are two possibilities.

Chapter 8 on Applets and Java describes the Java security model, which signed JavaScript scripts must subscribe to. From the immediately practical perspective, the key points for 4.0 browsers are:

Here is a simple example of a signed script, for Netscape 4.0 browsers. This example turns the user's toolbars on and off every second. That'll teach them to think again before accepting signed scripts ...

<HTML><BODY>
<SCRIPT ARCHIVE="sample.jar" ID="1">
function handler()
{
  alert('Very cautious of you - commendable');
  return true;
}

window.onerror = handler;         // called if user denies access

function flash_toolbars()
{
  netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserWrite");
  window.personalbar.visible = ! window.personalbar.visible;
  window.toolbar.visible     = ! window.toolbar.visible;
  netscape.security.PrivilegeManager.disablePrivilege("UniversalBrowserWrite"); 
  setTimeout('flash_toolbars()',500);
}
flash_toolbars();
</SCRIPT></BODY></HTML>

Signing Scripts

Once the client-side JavaScript content is created, that content must be signed. Signing the content lets the user confirm the origin of the script. They can then make a decision about whether to accept it or not. Signing scripts is different for Netscape and Microsoft 4.0 browsers.

Signing In Theory

The big three sources of confusion over signing are human roles, terminology, and how it all hangs together.

Human roles means who is providing the secure information, and what the intended audience is. For signed scripts, the script writer is providing the information, and the intended audience is any web user who will accept the script. This might seem obvious, but there are other kinds of signing that can happen on the Internet. Apart from similarly signed objects like plugins and applets, whole web sites can be signed, or a single e-mail note can be signed. For these other applications, the roles can be different. Here scripts are the focus.

Some terminology. The central concept is a digital certificate, or digital ID. This is the thing that is exposed to users, and is just a piece of data like everything else in computing. Certificate authorities (or CAs) are organizations that issue certificates. Certificates contain digital signatures which identify specific individuals. Developers have to manage digital signatures. Digital signatures are formed using techniques called message digests and hashes. Tools used by developers and users that aid the signing process implement these techniques. At the bottom of the pile is a theory called public key encryption, which makes the whole system go. If the developer loses his personal keys that are part of the public key encryption method, it's all over—start again at the top with a new certificate.

Why all these concepts? Because it matches the way people work. Suppose you were a bank, and a customer asked you for a line of credit, like a credit card or a home loan. You wouldn't just supply the money without checking the person out—you would ask for proof of identity. If the person just pointed to themselves and said "This is me", you wouldn't be satisfied. You would require them to do two things: provide proof, and provide a signature. Proof just means getting other people you trust to point to that person and say "Yes, he is who he says he is". Those other trustworthy bodies tend to be large, conservative organizations, like other banks, social security, medical benefits or driving registration authorities. Once proof is produced, each time the customer asks to withdraw money, their signature is provided, and you contact your trusted friends to see if there have been any problems with that signature since its last use. In the real world this last check might be relaxed, but not in the Internet.

In the case of the Web, the user is the bank; the script writer is the customer seeking access to the browser's features. The web browser holds certificates for a number of trustworthy bodies—certificate authorities. The script writer has a code-signing certificate issued by a certificate authority, who has scrutinized the script writer first. The script writer signs scripts with a pen (a signing tool) and ink (the keys supplied with the certificate), and includes a photocopy (certificate) of the signature of the trustworthy body (the certificate authority) to confirm his identity. When the user loads the signed script, the script writer's signature is examined. If it is unknown, the certificate authority's signature is examined. If it is a known certificate authority the script writer's signature passes, the script is accepted, and the script writer can get at the browser's secure features. The user can be warned via special browser dialog popups when this is happening. These dialogs serve to explain to the user who wants to do what to their browser.

So much for theory.

Signing In Practice

In practice, there are three different approaches:

For these processes, the script writer needs to be properly setup. The requirements are

a computer that has installed the browser that is the target browser for your end-user of the web page containing the signed script. Ideally this should be your development computer as well. If not, you will need FTP access to that development computer. Your browser computer needs Web access. You need an email account that you can read, but it doesn't have to be on your computer (i.e. RocketMail remote email accounts are sufficient).

You must also have a certificate in order to do the signing.

Doing without the hassle

As a developer, the signing process can get in the way of your development, slowing you down. To get going quickly you have two choices: disable security or develop using local files only. Afterwards, you can re-instate security or move the files to a web server. To disable security, read the section above entitled 'Other Risks'. Developing locally means using a file: URL for the topmost document and keeping all references relative so that the files can be easily moved later.

Obtaining a Certificate

All of the signing methods require that you obtain a personal certificate. There are four classes of certificate, ranging from 1 to 4. Class 1 one means minimal identity checks on you. Class 4 means even your hair follicles have been inspected. For testing, Class 1 is sufficient, but only Class 2 and onwards carry sufficient credibility to count for anything in the real world. Class 2 and onwards are not free. Most of the popular CA organizations don't bother supplying Class 1 certificates.

Certificates require numerous personal details, and a method of payment. You'll also have to wait several days. There are different kinds of certificates, so get the right one: a developer, code or object signing certificate (all the same thing).

The certificates used for testing in this book came from Thawte Certification, http://www.thawte.com. Their service is international and doesn't currently suffer from U.S.-specific restrictions. It also allows you to deal with a more local representative who can comply with your country's specific privacy laws. Very handy if you don't like accumulating charges for international phone calls.

Actually acquiring the certificate starts with applying via the Certificate Authority's web site, using your browser to fill in a form. Next you do the paperwork and payment. Finally, when the certificate is ready you retrieve it from the CA's web site, again using your browser. This last step appears to happen by magic, but just follow the instructions and use a simple nickname for the certificate, avoiding a password if possible. As for the discussion on cookies further on in this chapter, your browser is responsible for maintaining the certificate. Your browser is actually a certificate database, storing all the certificates you ever acquire in browser configuration files. Once the certificate is stored, you can view its details via the browser's security options.

There is one other piece of data that is stored. This is your encryption key for the certificate. It is stored in a separate file, often with a .p12 extension. Lose this file, and you've lost control of your certificate. If you accidentally delete the certificate, you can get it back if you have this file. Otherwise, this file doesn't come into play.

Object signing

Object signing signs things stored outside an HTML document only. Applets, plugins and .js files are examples, but this method doesn't sign anything between <SCRIPT> and </SCRIPT> tags. This is the simplest way to sign Netscape scripts. If you can limit your client-side JavaScript to external .js files only, do it this way. This means event handlers must be assigned from scripts, not specified in HTML tags, which is a lot of bother from the script writer's perspective, but actual signing is easier. A simple example which illustrates signing and use of signed features by toggling the location bar:

// greeting.js

netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserWrite");
top.locationbar.visible = ! top.locationbar.visible;
netscape.security.PrivilegeManager.disablePrivilege("UniversalBrowserWrite");

if ( Math.random() > 0.5 )
  document.write('Happy Birthday!<BR>');
else
  document.write('Merry Christmas!<BR>');
<!-- object.htm -->
<HTML><BODY>
Welcome to the random acts of kindness page. Just for you:<BR>
<SCRIPT ARCHIVE="greet.jar" SRC="greeting.js"></SCRIPT>
</BODY></HTML>

You can't sign a plain .js file. The file must be put inside a JAR archive. A JAR archive has two parts: a JAR format, and a JAR file. The JAR format is a group of files set up in a particular arrangement. A JAR file is a single file that collects together all the files in the group. The JAR format is quite detailed and tricky. You can read about it here if you wish: http://developer.netscape.com/library/documentation/signedobj/jarfile/index.html.

It's hard work and error prone assembling a JAR file by hand, so it's better to use a tool. Netscape has two tools. One of these is the JAR Packager, an applet that provides a simple, handy GUI that does the job. Because the applet is stored on your local computer, rather than downloaded from a remote URL, it can create the JAR file locally as well. For some reason, this tool has virtually disappeared from Netscape's Web site—you may have to buy Mission Control 4.0 (not a cheap utility) in order to get it.

The alternative is a command-line tool called Zigbert, which is free. Zigbert suffers from slow development, probably because it currently has no competitor. At this time of writing, version 0.6 is the latest. Do not use version 0.5—buggy. It is available for Sun Solaris, Microsoft Windows 95/NT and Silicon Graphics IRIX computers. Look here for documentation and a download location: http://developer.netscape.com/software/signedobj/. With Zigbert, you can look forward to several manual steps, and in the case of a PC, the DOS prompt. Presumably version 1.0 will improve this situation, but you can get by with 0.6.

What you can do with Zigbert 0.6:

What you can't do with Zigbert 0.6:

The Zigbert download provides zip and unzip tools to cover the latter omission, the former requires hand-copying files. The Zigbert manual explains the gory details, but in summary, get the certificate from the Certificate Authority first and then follow these steps:

Copy the key3.db and cert7.db Netscape certificate files to the same directory.

Sign using the certificate nickname: zigbert -d"." -k"my thawte cert" test

Move to the test directory: cd test

Make the JAR file using the supplied zip program: zip -r greet.jar *

Move the JAR file to the same directory as object.htm .

Your author had problems with Zigbert for his particular PC setup, which this fairly radical command fixed:

copy C:\windows\system\msvcrt40.dll C:\windows\system\msvcrtd.dll

Only do this if you know what it means, or if you're stuck and don't have an msvcrtd.dll already.

Your signed JavaScript should now run in the browser without any user warnings and without any security hobbles.

Page signing

The Netscape object signing case above is all very well, but it doesn't allow signing of event handlers and inline JavaScript code, only .js files. An extra level of complexity is required to cover this more extensive requirement. Consider this example, similar to the last:

<!-- page.htm -->
<HTML><BODY>
<SCRIPT ARCHIVE="greet2.jar" SRC="greeting2.js"></SCRIPT>
<FORM>
<SCRIPT ID=1>

netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserWrite");
top.locationbar.visible = ! top.locationbar.visible;
netscape.security.PrivilegeManager.disablePrivilege("UniversalBrowserWrite");

document.write('Random act of kindness button: ');
</SCRIPT>
<INPUT TYPE="button" VALUE="Go Ahead" ONCLICK="greet()" ID=2>
</FORM></BODY></HTML>

and the greeting2.js file:

// greeting2.js
function greet()
{
  if ( Math.random() > 0.5 )
    alert('Happy Birthday!');
  else
    alert('Merry Christmas!');
}

As for the last section, the Zigbert tool is required. Again, the 0.6 release is lacking in functionality.For page signing the situation is more serious: there is almost no functionality in Zigbert to support page signing. However, the Zigbert download file includes a workaround. The file signpages.pl is supplied to do the job. This tool takes the certificates (you copy them into place again) and the HTML file containing the JavaScript, and produces a JAR file using zigbert, zip and an ounce of intelligence.

There is one major catch. signpages.pl is written in the Perl language! Fortunately, Perl is a free tool. The web site http://www.perl.com is a good starting point for information about Perl. A hitch with Perl is that it is ultimately available in C code which must be compiled up before you can use it. For this task, Perl is just a means to an end, so the Perl executable is all you need to find. Not too hard if you're working on Unix, but problematic on the PC. Look here for a copy of Perl for Windows 95/NT ftp://ftp.netinfo.com.au/pub/perl/CPAN//ports/win95/Standard/x86 Files with a 'tar.gz' extension can be unpacked under Windows by renaming them with a '.tgz' extension and then using an unpacking tool such as 'WinZip'.

Perhaps you might have Perl installed in C:\local\perl. Make sure the PATH variable includes the directory containing zigbert and zip, and then use the magic command::

\local\perl\bin\perl signpages.pl -d"." -k"my thawte cert" page.htm

The signpages.pl script will warn you if any <SCRIPT> blocks are missing ID attributes, so you can't get a bad JAR file.

You now have a JAR file ready to use without any security warnings or hobbles in place. If you want to check that the page signing process does secure the HTML file against tampering, try removing one of the ID attributes and reload the page. The browser will now report that the page is unsigned when the page is reloaded.

© 1997 by Wrox Press. All rights reserved.