Monday, April 25, 2011

WEB BROWSER SECURITY MODELS

A variety of security controls are placed in web browsers. The key to hacking web
applications is to find a problem in one of the browser security controls or circumvent
one of the controls. Each security control attempts to be independent from the others, but
if an attacker can inject a little JavaScript in the wrong place, all the security controls
break down and only the weakest control remains—the same origin policy.
The same origin policy generally rules all security controls. However, frequent flaws
in web browsers and in browser plug-ins, such as Acrobat Reader, Flash, and Outlook
Express, have compromised even the same origin policy.
In this chapter, we discuss three browser security models as they were intended to be:
• The same origin policy
• The cookies security model
• The Flash security model
We also discuss how to use a little JavaScript to weaken some of the models.
Same Origin/Domain Policy
The same origin policy (also known as same domain policy) is the main security control
in web browsers. An origin is defined as the combination of host name, protocol, and port
number; you can think of an origin as the entity that created some web page or information
being accessed by a browser. The same origin policy simply requires that dynamic
content (for example, JavaScript or VBScript) can read only HTTP responses and cookies
that came from the same origin it came from. Dynamic content may not read content
from a different origin than from where it came. Interestingly, the same origin policy
does not have any write access control. As such, web sites can send (or write) HTTP
requests to any other web site, although restrictions may be placed on the cookies and
headers associated with sending such requests to prevent cross site requests.
The same origin policy may best be explained through examples. Suppose I have a
web page at http://foo.com/bar/baz.html with JavaScript in it. That JavaScript can
read/write some pages and not others. Table 2-1 outlines what URLs the JavaScript from
http://foo.com/bar/baz.html can access.
Exceptions to the Same Origin Policy
Browsers can be instructed to allow limited exceptions to the same origin policy
by setting JavaScript’s document.domain variable on the requested page. Namely, if
http://www.foo.com/bar/baz.html had the following in its page,
then http://xyz.foo.com/anywhere.html can send an HTTP request to http://www.foo.com/bar/baz.html and read its contents.
In this case, if an attacker can inject HTML or JavaScript in http://xyz.foo.com/
anywhere.html, the attacker can inject JavaScript in http://www.foo.com/bar/baz.html,
too. This is done by the attacker first injecting HTML and JavaScript into http://xyz
.foo.com/anywhere.html that sets the document.domain to foo.com, then loads an
iframe to http://www.foo.com/bar/baz.html that also contains a document.domain set
to foo.com, and then accesses the iframe contents via JavaScript. For example, the
following code in http://xyz.foo.com/anywhere.html will execute a JavaScript alert()
box in the www.foo.com domain:
Thus, document.domain allows an attacker to traverse domains.
In Firefox and Mozilla browsers, attackers can manipulate document.domain with
__defineGetter__() so that document.domain returns any string of the attacker’s
choice. This does not affect the browser’s same origin policy as it affects only the
JavaScript engine and not the underlying Document Object Model (DOM), but it could
affect JavaScript applications that rely on document.domain for backend cross-domain
requests. For example, suppose that a backend request to http://somesite.com/GetInfor
mation?callback=callbackFunction responded with the following HTTP body:
function callbackFunction() {
if ( document.domain == "safesite.com") {
return "Confidential Information";
}
return "Unauthorized";
}
An attacker could get the confidential information by luring a victim to the attacker’s
page that contained this script:
This HTML code sets the document.domain via __defineGetter__() and makes
a cross-domain request to http://somesite.com/GetInformation?callback=callback
Function. Finally, it calls sendInfoToEvilSite(callbackFunction()) after 1.5
seconds—a generous amount of time for the browser to make the request to somesite.
com. Therefore, you should not extend document.domain for other purposes.
What Happens if the Same Origin Policy Is Broken?
The same origin policy ensures that an “evil” web site cannot access other web sites, but
what if the same origin policy was broken or not there at all? What could an attacker do?
Let’s consider one hypothetical example.
Suppose that an attacker made a web page at http://www.evil.com/index.html that
could read HTTP responses from another domain, such as a webmail application, and the
attacker was able to lure the webmail users to http://www.evil.com/index.html. Then
the attacker would be able to read the contacts of the lured users. This would be done
with the following JavaScript in http://www.evil.com/index.html:
All your contacts are belong to us. :)
Step 1 uses an iframe named WebmailIframe to load http://webmail.foo.com/
ViewContacts, which is a call in the webmail application to gather the user’s contact list.
Step 2 waits 1 second and then runs the JavaScript function doEvil(). The delay ensures
that the contact list was loaded in the iframe. After some assurance that the contact list
has been loaded in the iframe, doEvil() attempts to access the data from the iframe in
Step 3. If the same origin policy was broken or did not exist, the attacker would have the
victim’s contact list in the variable victimsContactList. The attacker could send the
contact list to the evil.com server using JavaScript and the form in the page.
The attacker could make matters worse by using cross-site request forgery (CSRF) to
send e-mails on behalf of the victimized user to all of his or her contacts. These contacts
would receive a seemingly legitimate e-mail that appeared to be sent from their friend,
asking them to click http://www.evil.com/index.html.
Note that if the same origin policy were broken, then every web application would be
vulnerable to attack—not just webmail applications. No security would exist on the web.
A lot of research has been focused on breaking the same origin policy. And once in a
while, some pretty astonishing findings result.
Cookie Security Model
HTTP is a stateless protocol, meaning that one HTTP request/response pair has no
association with any other HTTP request/response pair. At some point in the evolution
of HTTP, developers wanted to maintain some data throughout every request/response
so that they could make richer web applications. RFC 2109 created a standard whereby
every HTTP request automatically sends the same data from the user to the server in an
HTTP header called a cookie. Both the web page and server have read/write control of
this data. A typical cookie accessed through JavaScript’s document.cookie looks like
this:
CookieName1=CookieValue1; CookieName2=CookieValue2;
Cookies were intended to store confidential information, such as authentication
credentials, so RFC 2109 defined security guidelines similar to those of the same domain
policy.
Servers are intended to be the main controller of cookies. Servers can read cookies,
write cookies, and set security controls on the cookies. The cookie security controls
include the following:
• domain This attribute is intended to act similarly to the same origin policy but
is a little more restrictive. Like the same origin policy, the domain defaults to the
domain in the HTTP request Host header, but the domain can be set to be one
domain level higher. For example, if the HTTP request was to x.y.z.com, then
x.y.z.com could set cookies for all of *.y.z.com, and x.y.z.com cannot set cookies
for all of *.z.com. Apparently, no domain may set cookies for top level domains
(TLDs) such as *.com.
• path This attribute was intended to refine the domain security model to
include the URL path. The path attribute is optional. If set, the cookie is sent
only to the server whose path is identical to the path attribute. For example, say
http://x.y.z.com/a/WebApp set a cookie with path /a; then the cookie would
be sent to all requests to http://x.y.z.com/a/* only. The cookie would not be
sent to http://x.y.z.com/index.html or http://x.y.z.com/a/b/index.html.
• secure If a cookie has this attribute set, the cookie is sent only on HTTPS
requests. Note that both HTTP and HTTPS responses can set the secure
attribute. Thus, an HTTP request/response can alter a secure cookie set over
HTTPS. This is a big problem for some advanced man-in-the-middle attacks.
• expires Usually, cookies are deleted when the browser closes. However, you
can set a date in the Wdy, DD-Mon-YYYY HH:MM:SS GMT format to store the
cookies on the user’s computer and keep sending the cookie on every HTTP
request until the expiry date. You can delete cookies immediately by setting the
expires attribute to a past date.
• HttpOnly This attribute is nowrespected by both Firefox and Internet Explorer. It
is hardly used in web applications because it was only available in Internet Explorer.
If this attribute is set, IE will disallow the cookie to be read or written via JavaScript’s
document.cookie. This intended to prevent the attacker from stealing cookies and
doing something bad. However, that attacker could always create JavaScript to do
equally bad actions without stealing cookies.
Security attributes are concatenated to the cookies like this:
CookieName1=CookieValue1; domain=.y.z.com; path=/a;
CookieName2=CookieValue2; domain=x.y.z.com; secure
JavaScript and VBScript are inaccurately considered extensions of the server code, so
these scripting languages can read and write cookies by accessing the document.cookie
variable, unless the cookie has the HttpOnly attribute set and the user is running IE. This
is of great interest to hackers, because cookies generally contain authentication credentials,
CSRF protection information, and other confidential information. Also, Man-in-the-
Middle (MitM) attacks can edit JavaScript over HTTP.
If an attacker can break or circumvent the same origin policy, the cookies can be
easily read via the DOM with the document.cookie variable. Writing new cookies is
easy, too: simply concatenate to document.cookie with this string format:
var cookieDate = new Date ( 2030, 12, 31 );
document.cookie += "CookieName=CookieValue;" +
/* All lines below are optional. */
"domain=.y.z.com;" +
"path=/a;" +
"expires=" + cookieDate.toGMTString() + ";" +
"secure;" +
"HttpOnly;"
Problems with Setting and Parsing Cookies
Cookies are used by JavaScript, web browsers, web servers, load balancers, and other
independent systems. Each system uses different code to parse cookies. Undoubtedly,
these systems will parse (and read) cookies differently. Attackers may be able to add or
replace a cookie to a victim’s cookies that will appear different to systems that expect the
cookie to look the same. For instance, an attacker may be able add or overwrite a cookie
that uses the same name as a cookie that already exists in the victim’s cookies. Consider
a university setting, where an attacker has a public web page at http://public-pages.
university.edu/~attacker and the university hosts a webmail service at https://webmail
.university.edu/. The attacker can set a cookie in the .university.edu domain that will
be sent to https://webmail.university.edu/. Suppose that cookie is named the same as
the webmail authentication cookie. The webmail system will now read the attacker’s
cookie.
The webmail system may assume the user is someone different and log him or her in to
a different webmail account. The attacker could then set up the different webmail account
(possibly his own account) to contain a single e-mail stating that the user’s e-mails were
removed due to a “security breach” and that the user must go to http://public-pages.
university.edu/~attacker/reAuthenticate (or a less obviously malicious link) to sign in
again and to see all his or her e-mail. The attacker could make the reAuthenticate link look
like a typical university sign-in page, asking for the victim’s username and password. When
the victim submits the information, the username and password would be sent to the
attacker. This type of attack is sometimes referred to as a session fixation attack, where the
attacker fixates the user to a session of the attacker’s choice.
Injecting only cookie fragments may make different systems read cookies differently,
too. Note that cookies and access controls are separated by the same character—a
semicolon (;). If an attacker can add cookies via JavaScript or if cookies are added based
on some user input, then the attacker could add a cookie fragment that may change
security characteristics or values of other cookies.
Parsing Cookies
Test for these types of attacks. Assume that man-in-the-middle attacks will be able to
overwrite even cookies that are set secure and sent over Secure Sockets Layer (SSL).
Thus, check the integrity of cookies by cross-referencing them to some session state. If
the cookie has been tampered with, make the request fail.
Using JavaScript to Reduce the Cookie Security Model
to the Same Origin Policy
The cookie security model is intended to be more secure than the same origin policy,
but with some JavaScript, the cookie domain is reduced to the security of the same origin
policy’s document.domain setting, and the cookie path attribute can be completely
circumvented.
We’ll use the university webmail example again where an attacker creates a web
page at http://public-pages.university.edu/~attacker/ and the university has a webmail
system at http://webmail.university.edu/. If a single page in http://webmail.university
.edu/ has document.domain="university.edu" (call the page http://webmail
.university.edu/badPage.html), then the attacker could steal the victim’s cookies by
luring him or her to http://public-pages.university.edu/~attacker/stealCookies.htm,
which contains the following code:
Protecting Cookies
Use the added features in the cookie security model, but do not rely on the added security
features in the cookie security model. Simply trust the same origin policy and sculpt
your web application’s security around the same origin policy.
Flash Security Model
Flash is a popular plug-in for most web browsers. Recent versions of Flash have very
complicated security models that can be customized to the developer’s preference. We
describe some interesting aspects to Flash’s security model here. However, first we
briefly describe some interesting features of Flash that JavaScript does not possess.
Flash’s scripting language is called ActionScript. ActionScript is similar to JavaScript
and includes some interesting classes from an attacker’s perspective:
• The class Socket allows the developer to create raw TCP socket connections
to allowed domains, for purposes such as crafting complete HTTP requests
with spoofed headers such as referrer. Also, Socket can be used to scan some
network computers and ports accessible that are not accessible externally.
• The class ExternalInterface allows the developer to run JavaScript in
the browser from Flash, for purposes such as reading from and writing to
document.cookie.
• The classes XML and URLLoader perform HTTP requests (with the browser
cookies) on behalf of the user to allowed domains, for purposes such as cross-
domain requests.
By default, the security model for Flash is similar to that of the same origin policy.
Namely, Flash can read responses from requests only from the same domain from which
the Flash application originated. Flash also places some security around making HTTP
requests, but you can make cross-domain GET requests via Flash’s getURL function.
Also, Flash does not allow Flash applications that are loaded over HTTP to read HTTPS
responses.
Flash does allow cross-domain communication, if a security policy on the other
domain permits communication with the domain where the Flash application resides.
The security policy is an XML file usually named crossdomain.xml and usually located
in the root directory of the other domain. The worst policy file from a security perspective
looks something like this:
This policy allows any Flash application to communicate (cross-domain) with the
server hosting this crossdomain.xml file.
The policy file can have any name and be located in any directory. An arbitrary
security policy file is loaded with the following ActionScript code:
System.security.loadPolicyFile("http://public-" +
"pages.univeristy.edu/crossdomain.xml");
If it is not in the server’s root directory, the policy applies only to the directory in
which the policy file is located, plus all subdirectories within that directory. For instance,
suppose a policy file was located in http://public-pages.university.edu/~attacker/
crossdomain.xml. Then the policy would apply to requests such as http://public-
pages.university.edu/~attacker/doEvil.html and http://public-pages.university.edu
/~attacker/moreEvil/doMoreEvil.html, but not to pages such as http://public-pages
.university.edu/~someStudent/familyPictures.html or http://public-pages.university
.edu/index.html.
Policy files are forgivingly parsed by Flash, so if you can construct an HTTP request
that results in the server sending back a policy file, Flash will accept the policy file. For
instance, suppose some AJAX request to http://www.university.edu/Course
Listing?format=js&callback=
from%20domain="*"/> responded with the following:
() { return {name:"English101",
desc:"Read Books"}, {name:"Computers101",
desc:"play on computers"}};
Then you could load this policy via the ActionScript:
System.security.loadPolicyFile("http://www.university.edu/" +
"CourseListing?format=json&callback=" +
"" +
"" +
"");
This results in the Flash application having complete cross-domain access to http://
www.university.edu/.
Many people have identified that if they can upload a file to a server containing an
insecure policy file that could later be retrieved over HTTP, then System.security
.loadPolicyFile() would also respect that policy file. Stefan Esser of www.hardened-
php.net showed that placing an insecure policy file in a GIF image also works. (See
“References and Further Reading” at the end of the chapter for more information.)
In general, it appears that Flash will respect any file containing the cross-domain
policy unless any unclosed tags or extended ASCII characters exist before
policy>. Note that the MIME type is completely ignored by Flash Player.
Protecting Against Reflected Policy Files
When sending user-definable data back to the user, you should HTML entity escape the
greater than (>) and less than (<) characters to > and <, respectively, or simply
remove those characters.