For users of JavaScript enabled browsers, requesting a URL represents a risk if it contains JavaScript. Without security hobbles, JavaScript could seize control of the browser, or possibly the browser's computer. The simplest form of privacy for the user is to turn JavaScript support off in the browser via the browser preferences. This can't be done from within a JavaScript script, except via the navigator.preference
property in Netscape Navigator 4.0, and even then the browser must be shut down and re-started for it to take effect.
A number of JavaScript bugs that create security risks have been identified in version 3.0 and 4.0 browsers. To avoid as many of these as possible, make sure you have the latest version of the browser available. For example, at this time of writing Netscape Navigator 4.04 is the latest, not 4.02 or 4.01. This Web page: http://www-genome.wi.mit.edu/WWW/faqs/wwwsf?/html
is a good starting point for JavaScript security bug information.
There are several kinds of security hobbles that protect the browser user's privacy.
It is nearly always true that client-side JavaScript is restrained from doing any input or output without the user's permission. Generally, the user can be confident that no changes are occurring to the local computer outside of the browser, but there are exceptions. Writing to files, to network connections, and to the display are the main sources of risk. Of these, display-related restrictions are discussed further on. The file and network cases are generally impossible, except for the following possibilities.
If a browser loads a script directly from the local computer without using a web server, then that script can do anything the language and host objects allow. The user may get a warning and an option to back out, depending on how the browser's security preferences are set up. Internet Explorer 3.0 with JScript 2.0 (and later versions) allows script writers to read, write and create any file on the browser's computer using JavaScript facilities directly. This is achieved with the JavaScript FileSystemObject
and TextStream
objects
.
JScript 3.0 adds the File
and Folder
objects which allow local files to be removed or renamed as well as created or changed, but this is only possible for Internet Explorer 4.0, and browser security options must be lowered by the user as well.
Netscape JavaScript can also write to local files, but there is no direct support in the language. Instead, Java objects supply this functionality; those objects must be accessed via LiveConnect. Here is an example of writing a user-supplied string to a user-supplied filename. See the Chapter 8 to understand the mechanics at work here:
<HTML><BODY><SCRIPT>
function save_it(filename, filedata);
{
netscape.security.PrivilegeManager.enablePrivilege("UniversalFileWrite");
var jo_file = new java.io.FileOutputStream(filename);
var jo_stream = new java.io.DataOutputStream(jo_file);
jo_stream.writeChars(filedata);
jo_stream.close();
netscape.security.PrivilegeManager.disablePrivilege("UniversalFileWrite");
}
</SCRIPT>
<FORM>
File Name: <INPUT TYPE="text" NAME="file"><BR>
File Data: <INPUT TYPE="text" NAME="data"
ONCHANGE="save_it(this.form.file.value, this.value)">
</FORM></BODY></HTML>
This example also requires some agreement from the user before it can go ahead. See the Security section.
A browser that supports Java applets can make network connections. With ActiveX or LiveConnect, JavaScript scripts can control these applet connections. Chapter 8 describes how.
However, without a security agreement, the connections are limited. Java applets are downloaded via a URL in an <APPLET>
or <OBJECT>
HTML tag. Only the computer supplying the page for that URL can be connected to. If the tag includes a CODEBASE
URL, then the computer at that codebase URL is the only possibility for connections.
A more subtle possibility stems from the fact that one Java applet may converse directly with another. However, the part of the Java system that loads applets also ensures that applets from different sites can't communicate. This prevents one applet from exploiting the network connections available to another.
Cookies are described in a later section of this chapter. The cookie data available to web servers doesn't include any very private information such as the user's name, so risk from cookies is minimal. Long-lived cookies are stored in a file on the browser's computer. However, this file is a plain data file with a maximum size of approximately 1200 Kilobytes for Netscape. Other than taking up space, this file doesn't do anything outside the browser environment. A cookie file will normally be only one or two Kilobytes.
The netscape.cfg
file of Netscape 4.0 browsers can be configured to give away control of the user's preferences. A JavaScript script stored elsewhere under someone else's control assumes the task. In a company environment, this usually poses no privacy risks.
The main form of output from client-side JavaScript is not to files and network connections, but to the browser itself. JavaScript can affect windows in a browser in three ways:
The user can have more than one browser window open at a time. The user can also have more than one URL per window if frames are present, and those URLs can come from different web sites. If it were not for a number of security hobbles, JavaScript could use its control over windows to:
Two concepts are central to the window security features that prevent these things from happening.
To understand window security restrictions, first take a step back and reflect on the ECMAScript standard.
In ECMAScript terminology, an 'execution environment' is a stage on which scripts can perform (execute), whether they are standalone or client-side scripts. When an execution environment is created, such as in a browser, a good question is: what is the current object? The standard states that all built-in objects and built-in functions in a script are part of a special 'global' object, which is the current scope when that script starts executing. Even functions like parseInt()
can therefore be viewed as a method of an object.
However, there is not just one 'global' object in a JavaScript-capable web browser. Instead, the browser has a 'global' object for each browser window currently open. These global objects each have a property 'window'
which refers back to that global object. These window properties provide a named hook so that the script writer can get access to that global object.
Each global object is like a bucket in which all the data specific to the window can be stored, making it easy to access. Therefore, the 'window'
property sits at the top of a hierarchy (or a pool) of data that includes all the JavaScript variables, objects and host objects in that window. If the window is closed, everything owned directly or indirectly by the global object is tracked down and cleaned up.
This makes each window fully self-contained and independent. It makes it easy to keep scripts from interfering with other windows, since they can only ultimately belong to one global object. Viewed from the JavaScript perspective, the browser is not a single hierarchy or pool of properties and objects, it is a number of them.
Unfortunately, life is rarely that simple. In reality, one window will often contain JavaScript variables that refer to objects or properties in other windows. A simple example is the window.open()
method—the return value can be stored in a variable in the containing window but refers to the global object in the newly created window. Similarly, the newly created window's global object has an 'opener'
property referring back to the old window.
At the time of writing this, the ECMAScript standard doesn't specify how the communicating-between-globals system works. The answer for browsers is LiveConnect or ActiveX glue software. This glue is effectively invisible except when window ownership issues are important. The owner of a window is the host address of the window's main URL, for example 'www.this.com:80'
. Attempts to work with properties or methods in a different window first have to pass checks based on the owners of the two windows. This script can be used to show the dynamic behavior involved:
<HTML><BODY><SCRIPT>
var win2 = null;
function open_local() { top.win2=window.open(window.location.href,'test'); }
function open_remote() { top.win2=window.open('http://www.wrox.com','test'); }
function show_it()
{
window.document.forms[0].one.value = top.win2;
window.document.forms[0].two.value = top.win2.name;
window.document.forms[0].three.value = top.win2.location.href;
}
</SCRIPT><FORM>
<INPUT TYPE="button" VALUE="Open local window" ONCLICK="open_local()">
<INPUT TYPE="button" VALUE="Open remote window" ONCLICK="open_remote()">
<INPUT TYPE="button" VALUE="Show window details" ONCLICK="show_it()">
<INPUT TYPE="button" VALUE="Go backwards" ONCLICK="window.history.go(-1)">
<BR>
Type of win2: <INPUT NAME="one" TYPE="text"><BR>
Name of win2: <INPUT NAME="two" TYPE="text"><BR>
URL of win2: <INPUT NAME="three" TYPE="text"><BR>
</FORM></BODY></HTML>
When displayed, the document looks like this:
This HTML page has three purposes:
The 'Show window details' button is used to report the current state of the auto-created window.
The following discussion pertains to Netscape behavior. Before pressing either of the open buttons, reporting the current state produces an error because the second window is not open and therefore 'win2'
is not yet an object. If a local window is opened, the name and URL will display correctly. If a remote window is opened, then an error results trying to get its URL (assuming you don't own the Wrox Web site). If you navigate with that new window back to a local web page, either via the 'Open local window' button or directly using the window toolbars, the URL is accessible again.
When the window is off-limits, Netscape's error is:
"Access disallowed from scripts at http://mysite/tests/remote_test.htm
to documents in another domain".
This message assumes that the mysite
site is where you are doing the testing.
If the second window is closed, a number of obscure errors can occur, depending on the version and whether Java is enabled or not. It is better not to examine a closed window object, except to test if the window IS closed by looking at the boolean value window.closed
.
If this script is run with Internet Explorer 3.0 and Jscript 1.0, none of the second window's properties are accessible, including window.closed
. This shows that JavaScript inter-window access is not a requirement for all browser tasks.
Without security arrangements granting the script writer special privileges, some browser features can't be removed from the user's control. These are:
The Reference Section describes which methods require special privileges before they can be used. In particular, 'canvas' or 'kiosk' mode, in which a single window takes over the whole screen, requires special privileges for Netscape 4.0 browsers. For these browsers, the user can drop the above restrictions on scripts by changing their browser preferences as described in the 'Privacy For Scriptwriters' section.
Browsers are designed to limit the user to a fraction of the resources of the browser's computer:
Such memory protection systems aren't foolproof. Even for normal memory and non-ActiveX controls, this script fragment will bring most browsers quickly to their knees (don't try this unless you're willing to re-boot):
<HTML><BODY><SCRIPT>
var big_string = "double me up!";
while (true)
{
big_string = big_string + big_string; // 20 iterations equals all your memory...
}
</SCRIPT></BODY></HTML>
Memory limitations also apply to Java applets in Netscape Navigator. Sometimes these applets are 'cleaned up' to save memory, which can also impact JavaScript. See Chapter 8 for further details.
<HTML><BODY><SCRIPT>
var total = 234;
var new_items = 2555666;
function dumb_add() // addition for people with only one finger
{
while (new_items) // won't complete: 2,555,666 iterations > 1,000,000
{
new_items--;
total++;
}
}
dumb_add();
alert('New total is: '+total);
</SCRIPT></BODY></HTML>
In the workaround case below, the browser will still be busy 99% of the time, but because the executing script breaks off regularly for a millisecond, the browser is satisfied that the user still has a chance to do things. The browser will therefore be able to respond to user input, but only slowly, especially if that input means other scripts need to run. At the same time, the long-running script will be able to eventually complete all its processing.
<HTML><BODY><SCRIPT>
var total = 234;
var new_items = 2555666;
function dumb_add() // Do addition for people with only one finger
{
var steps = 10000; // don't run for too long
while (new_items && steps)
{
steps--;
new_items--;
total++;
}
if ( new_items )
setTimeout('dumb_add()',1);
else
alert('New total is: '+total);
}
dumb_add();
</SCRIPT></BODY></HTML>
There are other risks for the user when using a browser on the Internet, but few of them involve JavaScript. A few do:
prefs.js
file. That file is stored in the Netscape installation area, there is one for each browser user. Add this line and restart the browser:user_pref("signed.applets.codebase_principal_support", true);