|
Acknowledgment:
Written by James A. Whittaker, Mike Andrews on Feb 24th, 2006. Sample Chapter is provided courtesy of Addison Wesley Professional.
The concept of state, or the ability to remember information as a user travels from page to page within a site, is an important one for Web testers. Developers of Web applications must take it upon themselves to code state information so they can enforce rules about page access and session management. This chapter contains a series of attacks that will help determine if your Web application does this important task correctly and securely.
The concept of state, or the ability to remember information
as a user travels from page to page within a site, is an important one for Web
testers. The Web is stateless in the sense that it does not remember which page
a user is viewing or the order in which pages may be viewed. A user is always
free to click the Back button or to force a page to reload. Thus, developers of
Web applications must take it upon themselves to code state information so they
can enforce rules about page access and session management. This chapter
contains a series of attacks that will help determine if your Web application
does this important task correctly and securely.
This chapter presents the most common and notorious Web vulnerabilities.
Introduction
All Web sites have a designated "home" or "default" page that
Web designers intend as the starting point for visitors. From that start page,
users can navigate the various pages of the site by clicking hyperlink objects
embedded in the various pages of the site. Hyperlinks can be text, images, or
other objects on the page.
This is the way it is supposed to work anyway. The problem is that the Web
has no built-in mechanism that specifies which sequence of Web pages and forms
are presented to the user. This aspect of the Web is called
statelessness to denote that each page is delivered to users
without knowledge of where the users were previously or restrictions about where
they can go next. Users can simply type in the URL of the page they want to
load, skipping the start page and any other page they do not need to view.
If restrictions about page access are important, it is up to the Web
application to enforce this.
Statelessness is ideal when browsing for information (or
surfing, as it has become commonly known), but more has been
demanded of the Web than surfing static, standalone pages, and statelessness can
lead to any number of failures and security violations. Imagine surfing past the
pages where credit card numbers are entered and going directly to the page where
the receipt is displayed—obviously not something you want your own Web
application to do!
The burden of including state information in a Web application falls squarely
on the shoulders of the Web developer and the tools for adding such state
information to a Web application are not particularly sophisticated.
The first option is using forms and CGI
parameters, which allow the transfer of small amounts of data and
information to be passed from page to page, essentially allowing the developer
to bind together pairs of pages. More sophisticated state requirements mean that
data needs to be stored, either on the client or the server, and then made
available to various pages that have to check these values when they are loaded.
For example, we may store a flag on the server that indicates whether a user
has entered a valid credit card. The Web application will then only allow the
purchase pages to be loaded (and the purchase to be confirmed) if that flag is
set to the correct value.
Shopping carts, purchase history, shipment tracking, and other such features
require some state to be made available to the Web application. These features
and the need to store state in general (and attacks on that state data) are the
subject of this chapter.
Attack 6: Hidden Fields
One of the most basic ways of preserving state in Web pages is to hide data
in the page. That way as a user browses pages, state information can be carried
along, allowing the Web application to give the user a smooth browsing
experience.
The most common ways of doing this are to place data in hidden form fields or
to append data as CGI parameters to hyperlinks. Both methods have the same
effect, but hidden fields are less obvious to the user.
When a form is submitted to the Web server, each of the form fields is passed
to the server as GET or POST parameters. (Don’t worry about these at the
moment. We look at these in detail in the next attack.) But it’s not only
the fields that the user can see that are passed; hidden fields are passed, too,
and the Web application can read them just like normal fields, and understand
whatever data they contain. Developers sometimes favor hidden fields because
they are easy to include at design time. Hidden fields have two other benefits.
First, nontechnical people can maintain them in applications like FrontPage,
Dreamweaver, and so on. Second, they are not obvious to a casual user.
The problem is that hackers are not casual users. They can and will read
hidden fields. If the information these fields contain is useful in an attack,
you can safely assume that hackers will use it that way.
You can store numerous things in hidden form fields. Not all of them are
state related, but you should treat them with suspicion when they are
discovered. The basis of this attack is to look for hidden fields within forms,
analyze what they are used for, and try to change their values in ways that
would benefit an attacker.
When to Apply This Attack
The easiest way to determine if this attack is possible is to view the source
of the page and search for the string "hidden". Most form elements
follow this structure:
<input name="is" value="1234" ... >
along with the possibility of other, additional attributes. The type
"hidden" is one such attribute that appears in the source of a Web page,
as follows:
<input name="id" value="1234" type="hidden">
The most primitive way of modifying these form elements is to save the page
locally (using File, Save As in your browser while the page is displayed) and
remove the "type=hidden" text from the source (remembering, as always,
to change any relative links to absolute links so that everything still points
to the correct location when you reload the locally saved copy of the page).
This effectively changes the hidden field to a standard text box, which you can
see and modify directly in the browser.
An alternative way of identifying hidden fields is to use the browser’s
Document Object Model (DOM). Both Internet Explorer and Firefox have programming
interfaces that allow developers to query the document within the browser and
change some of its attributes. This functionality was originally intended for
dynamic HTML so that scripting languages like JavaScript or VBScript could
implement dynamic UI functionality, as described in Chapter 3, "Attacking
the Client."
Consider the DOM code that follows, which iterates over a document in
Internet Explorer and prints the names and values of all hidden fields:
using System;
using mshtml; // access to IE’s DOM
IHTMLElementCollection tags; // interface to HTML document
// iterate through all HTML tags
tags = HTMLDocument.all;
foreach (IHTMLElement tag in tags)
{
// Is the current tag an input tag?
if (string.Compare(tag.tagName,?INPUT?,true) == 0)
{
// cast to an input tag
IHTMLInputElement inputTag = (IHTMLInputElement)tag;
// Is it a hidden input field?
if (inputTag.type==?hidden?)
{
Console.Write(?hidden form field ??+inputTag.name+???+
?found. Value is ??+ inputTag.value+?? ?
// change the field value here
// inputTag.value=="somevalue";
}
}
}
It is straightforward to modify this code to change any of the hidden field
values to whatever value an attacker considers advantageous.
If you don’t want to write the code yourself, the PageSpy tool on the
CD in the back of this book uses this technique to list the hidden fields on a
page and allow changes—all from a simple graphical user interface
(GUI).
How to Perform This Attack
There is no easy recipe for this attack; it all depends on what hidden fields
you find on the page and the data they contain. The most universally useful
advice is to change values of hidden form fields and see what happens as
subsequent pages load. This should make problems with hidden fields apparent.
Consider the following example.
A really naive mistake that early Web developers made often and that people
still make today is saving product information on a page and passing that
information to subsequent pages as in the application shown in Figure
4-1. For
example, as in Figure
4-2, we may want to save a product’s price in a
hidden field to help the server calculate totals as the user browses a site. If
an attacker recognizes this field and modifies it, he can reduce the price of
the product to whatever he likes.
This is really the idea: Watch for information in all hidden fields, and ask
yourself whether an attacker would find the information advantageous.
Another important thing to note is that hidden fields are data passed from a
client machine to a Web server. Because hidden fields have no data type
associated with them, changing their values to be illegal, overly long strings
and special characters may result in crashing or otherwise adversely affecting
the Web server.
Finally, you can use hidden fields to store data such as the previous page
visited or the last selected action. This data can ensure that users follow the
required flow of the application and don’t jump to pages they
shouldn’t be able to access. Hidden fields can also store session
information, as we shall see in a later attack.
How to Protect Against This Attack
Avoid hidden fields wherever possible, and most especially on information
like price, quantity, page sequence, and other information you do not want your
users to change. Before using these fields for anything, evaluate the data that
the field contains for its security risk. Where you use hidden fields, limit
their exposure by obfuscating the field name (for example, by using something
less obvious than "price" or "password") and encrypting or
hashing the value to something less recognizable to the attacker.
This technique, however, relies on security by obscurity, and is almost
always broken over time. Something named cX24y is no more secure than something
named price, but it is harder to tell what the former is and determine if it is
important. If you do use hidden fields for something (they are not entirely
evil—a common usage is to include them in search forms so the script that
performs the functionality knows how to "brand" or frame the results),
ensure that the data is what you expect. Attackers can and will modify these
values.
Attack 7: CGI Parameters
Although hidden form fields are a good way of passing data between pages,
there is a big drawback in using this method: The user has to submit a form to
an "action handler," usually by pressing a button. It may seem like a
small point, but users are more used to clicking on hyperlinks or images for
their navigation than form Submit buttons.
CGI parameters are ideal for this task. After the parameters reach the server
they are accessed in the same way as form fields. (See the difference between
GET and POST form methods in the next sidebar, "The Difference Between GET
and POST Parameters.") You easily can attach CGI parameters to any
hyperlink.
When to Perform This Attack
CGI parameters are passed in a page request’s URL after the ? character
and are name-value pairs separated by & characters.
It’s easy to tell if the current page uses CGI parameters, because they
will be clearly shown on the browser’s address bar. Links from a given
page and their parameters should display on the browser’s status bar if
this functionality is enabled.
Other than their location, we attack CGI parameters in the same way that we
attacked hidden fields.
How to Perform This Attack
There is no single way of performing this attack. From an attacker’s
point of view, it all depends on what parameters he sees being passed from page
to page and what their values are. As with the previous attack, we have to
consider what advantage the information contained in the parameters represents
to an attacker.
Begin by browsing your target site and noting the address bar. Also use your
mouse to hover over clickable objects and note the URL that’s usually
shown at the bottom of the screen in the information bar. The data in a URL
after the question mark are CGI parameters. We need to understand what the data
represents and whether its exposure would benefit an attacker.
You can modify CGI parameters by editing the page’s HTML, as in the
hidden forms attack earlier, but for GET parameters, it is usually much easier
to request a target page, change the values in the browser’s address bar,
and request the page again. There are many attacks against CGI parameters, all
of which overlap with other attacks discussed in this book.
For example, if a parameter looks like it’s to be used to select an
item from a database (that is, the URL looks something like
http://www.companytotest.com?item=1234),
try changing the value and seeing what happens.1
This effectively asks the database for a different record than the one
originally requested. Perhaps this is not a severe security risk in most
circumstances, but imagine if the request was for a patient’s record in a
healthcare provider’s online system. You’ve just breached the
patient’s privacy in the worst sort of way. This is exactly the situation
we are trying to prevent, so apply this attack in a creative way, and make sure
these bugs are reported and fixed before your site goes live.
It helps to consider the common uses of CGI parameters, so let’s spend
some time talking about them.
CGI parameters are often used to pass user preferences. Take Google, for
example. If you look at any Google search, you’ll see the hl parameter,
which specifies what language to "brand" Google, as shown in Figure
4-5.
What happens if that parameter is changed, say to ’ru’? In this
case, Google changes its output to Russian. Changing the parameter to xx-hacker
results in Figure
4-6.
Another common use of CGI parameters is to keep track of which pages a user
has navigated successfully. For example, some pages might be restricted to users
who have been through a registration or authentication process. These parameters
often have short names (single characters aren’t uncommon) and can carry
the values of 1 (true/on) or 0 (false/off). Modifying the value may fool the Web
application into believing that the attacker has already registered.
Because Web applications are notoriously difficult to debug (attaching a
debugger and single stepping through code isn’t easy), some developers add
hidden debug parameters to their application. When these parameters are present,
the developers send additional output to the browser, often giving a trace of
internal application details such as database connections, SQL queries, and
variable states.
In normal use, these parameters aren’t present, so the end user is none
the wiser. Adding &debug=on, &debug=1, or &debug=true to the end of
the list of CGI parameters (order of parameters generally isn’t important,
but commonly debug parameters are appended after existing ones) is a simple test
to see if the developer has added this debug functionality. However, it’s
much easier to look at the application code to see if there are if (debug)...
statements. Say that instead of using simple Boolean values, the developer uses
a "magic" number, like 3141592654, to turn debug mode on. Using manual,
black-box testing, you may never discover this number—looking at the
source is much easier.
So far, we’ve talked about CGI parameters passed in the browser’s
address bar, which are known as GET parameters. We also mentioned POST
parameters, which you’ll be learning more about in the upcoming sidebar
titled "The Difference Between GET and POST Parameters." POST parameters
are not as obvious to the end user, or as easy to change, and are passed to the
Web server in a slightly different way than GET parameters. This means that we
cannot as easily modify them using techniques we have introduced thus far; we
must use something to help us. Enter Paros Proxy 0, the authors’ favorite
Web testing tool.
Paros is described more fully in Appendix C, "Tools," but it allows
you to see and modify all HTTP traffic to and from the Web server.
Numerous types of data are passed using CGI parameters. CGI is one of the
only mechanisms of passing data to subsequently loaded pages.
Therefore, a comprehensive list of attacks is impossible, and testers need to
carefully consider how each parameter may be misused. CGI parameters are the
delivery vector for most other attacks (cross-site scripting, SQL injection,
directory traversal, and so on) that we will be discussing. That’s why
knowing what parameters there are and how to change them is important.
How to Protect Against This Attack
Perhaps the best advice to defend against this attack and many other attacks
that originate on the client machine is to parse all input for validity. (You
may want to refer to the sidebar "Validating Input" in the previous
chapter for an in-depth discussion.)
Attack 8: Cookie Poisoning
Cookies are small files of textual data that a Web
application writes on a client’s hard drive. The Web application can then
reuse this data on subsequent visits to the site from that same computer. This
allows the Web site to remember a visitor and offer him customized or
personalized content based on the information stored in the cookie.
When people talk about cookie poisoning, it’s mostly
in the context of session hijacking (another attack described later in this
chapter). However, there’s much more to cookies than just session
identifiers.
Cookies are delivered in four forms that are the combination of two settings:
persistent or nonpersistent, and secure or nonsecure. The browser places
persistent cookies on the client hard disk until their expiry date. In contrast,
the browser destroys nonpersistent cookies (which are stored only in memory) as
soon as it closes. The secure setting for a cookie, though, is a bit misleading.
The cookie itself is not secured or encrypted in any way, but it is a directive
to the browser to send this cookie only over secure transport, which is
HTTP over SSL (HTTPS).
Although the data within a cookie is an obvious place to attack, cookies also
have the ability to expire after a specified date. This functionality often
ensures that users reidentify themselves after a period of time or sets some
time limit on accessing a resource. For example, a credit report might be valid
for only 30 days.
When to Apply This Attack
Like it or loathe it, users are deluged with cookies whenever they use the
Web. You can set up all browsers to warn users when a cookie is written to their
hard drive, but software like CookiePal
(http://www.kburra.com/cpal.html)
or CookieCrusher
(http://www.thelimitsoft.com/cookie/)
gives users more fine-grain control over what cookies they accept or reject and
how they view the cookies they have on their computer. Firefox has a lot of this
functionality built in.
How to Perform This Attack
Cookies are stored in predefined locations, with predefined formats, so
modifying their data manually is easy. In Firefox/Netscape, cookies are stored
in a cookies.txt file with a format shown in Figure
4-8.
Internet Explorer stores its cookies in c:/documents and
setting/%USERNAME%/cookies/ as individual text files in a format that needs some
explanation.
Each text file in the cookies directory is formatted as
username@sitename[1].txt. Therefore, if Joe visited Amazon.com, all his cookies
for that site would be stored in the file joe@amazon[1].txt, and on rare
occasions, the file would have the [2] postfix. Cookies inside the file are
separated by * on a single line, with the cookies formatted as shown in Figure
4-9.
What’s interesting about this cookie format is not the name, value, or
domain attributes, but the way the time and dates are stored.
Rather than storing the creation and expiry timestamps as the number of
seconds past midnight January 1, 1970 (the most common format), Internet
Explorer uses increments of 100 nanoseconds (10-7 seconds) since
January 1, 1601. Why Microsoft had to use such a fine-grained scale or go back
as far as the 1600s is beyond us, but it fits nicely into a 64-bit number. When
you’re saving cookies, however, this 64-bit value is broken into two
sections: time and date. Although the numbers seem difficult to interpret,
it’s possible to deduce the date and time from them. The bottom number of
the pair is the most significant because it shows time and date in units of
429.4967296 seconds since January 1, 1601. The top number shows the time since
the last unit of 429.4967296 seconds has passed, in units of 10-7
seconds.
For example, suppose that we check our credit rating with a fictitious site,
Simplecreditrating.com. We are given our credit rating report online, but it
expires in 30 days. Simplecreditrating.com enforces this policy by issuing a
cookie with the report ID that expires in a month. We can find the cookie
here:
c:/documents and settings/mike/cookies/
mike@ simplecreditreport[1].txt
Now we can open the cookie in WordPad, as shown in Figure
4-10.
If we change the 29592292 value to 29598326, we can access the report for an
extra 30 days. The designer of this Web site probably didn’t intend for us
to do that.
It’s not only the expiry timestamp of a cookie that we can change. We
can also change the value part of the cookie. We can change the report reference
number, 11223344, to another value in an attempt to read someone else’s
credit report.
Some Web applications have a "remember me" functionality, where
return visitors are automatically logged in or presented with custom content.
Because cookies are the only way to store state information on the client across
sessions, this is the obvious place to look to try to break this kind of
functionality. Viewing cookies when this functionality is available can reveal
usernames and passwords, or "magic" identifiers that are supplied to the
Web server in lieu of a user having to authenticate. All of these are attractive
targets for attackers.
In Attack 11, we’ll look at a related method whereby an attacker can
steal cookies.
How to Protect Against This Attack
Designers of the Web never intended cookies to be secure. Cookies were to be
an extension to HTTP that gave it some aspect of client-side state. However,
because cookie files are the only way to store state information across
browser sessions, Web designers have used them considerably and will likely
continue to use them.
If your Web application is relying on cookies to enforce expiration or you
really have to store sensitive data on the client, consider encrypting the
cookie. And don’t rely on the cookie’s own expiry date, because
that’s easy to tamper with.
Attack 9: URL Jumping
Because the Web is inherently stateless, users can jump to any page they want
to by typing the Universal Resource Locator (URL) in the browser’s address
bar and pressing Enter. Developers of Web applications often don’t want to
allow users this level of freedom because they might have a sequence of
operations that users have to follow, as depicted in Figure
4-11.
If the user were allowed to jump directly from the Checkout page to the
Delivery Info page, he may be able to receive his goods without paying for them.
This is only one such example. There are many occasions in a system where one
operation has to take place before another (for example, logging in before
reading an e-mail message, or selecting a group before posting a forum message).
The purpose of this attack is to identify actions in a Web application that
should be sequenced and attempt to jump into, around, or over certain steps by
browsing directly to them.
When to Apply This Attack
This attack often requires some understanding of the Web application and
exactly what it implements. You may want to go back to the page map we developed
in Chapter 2, "Gathering Information on the Target," and think about
sequences of pages or operations and the implications of jumping from page to
page without clicking the links that the application provides.
Begin by browsing the application as a legitimate, well-behaved user, and
note the addresses of pages visited along with their sequence. Using this list,
randomly enter addresses and see if the application produces meaningful error
messages or disallows access to specific pages.
How to Perform This Attack
For a poorly developed Web application, this attack is a task of
reconnaissance followed by entering page addresses into the browser’s
address bar. However, good Web developers understand the problem of users
breaking out of page sequences. As one means of protection against this attack,
these developers may compare the last visited page against the one a user
should have come from.
Developers can achieve this protection technique with any of the following
methods:
Using hidden fields or CGI parameters to store a page address or
identifier
Using cookies to store last visited pages or identifiers
Comparing where the user should have come from with the HTTP-REFERER
field
The first method, using hidden fields or CGI parameters with page addresses,
is the most insecure method because it is subject to the attacks described
earlier. It really only stops unsophisticated attackers; nonetheless, developers
use the technique because of the simplicity of including the hidden data at
design time. It’s relatively easy to change the field’s value or
even to add a required hidden field where necessary (in either the HTML source
or by capturing the page request using a proxy).
The second method, using cookies to store the last visited page, is slightly
more secure because cookies (especially temporary ones2) are harder
to modify as they are passed in the HTTP header—a place that users
can’t control through the browser.
GET /articles/news/today.asp HTTP/1.1
Accept: */*
Accept-Language: en-us
Connection: Keep-Alive
Host: localhost
Referer: http://www.myhomepage.com/links.asp
User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)
Accept-Encoding: gzip, deflate
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.0
Date: Thu, 13 Jul 2000 05:46:53 GMT
Content-Length: 2291
Content-Type: text/html
Set-Cookie: chocolatechip=DR2EO53DNSK2EMM5K2LSLJ5NEKE; path=/
Cache-control: private
<HTML>
[...html markup follows...]
Also note that in the HTTP request data, the referer field carries the
address of the page that initiated the request and may be used instead of
setting an explicit cookie.
In fact, it’s pretty easy to change the HTTP header. In modifying the
referer header and the cookie, you can use proxy tools such as Paros to change
the cookie’s or the referer’s value. You can also perform page
requests manually, as we will show in future attacks.
Regardless of which method the Web developer chooses to implement or how you
decide to attack it, the principle is the same: Request a page that a user
should not be able to jump directly to, and see if you can view it. If not,
modify the values of hidden fields, cookies, or the referer to try to force it
the hard way. If you see the page, you have a potential attack scenario and a
bug report to write.
How to Protect Against This Attack
There is no other way to protect against this attack except by restricting
the sequence in which you can view pages. This obviously requires storing the
last visited page, but as mentioned earlier, you can store this information in
numerous places, some of which an attacker can access.
The most secure place for the last visited page to be stored is on the
server, because users only have control over information on the client machine
and the information that the browser sends over the network. Many Web
application servers can store variables on the server (ColdFusion, Java
Servlets, ASP, PHP, and so on), but this requires the use of session variables
and opens up the possibility of session hijacking attacks, covered later in this
chapter.
If there is one preferred method of storing the last visited page (without
server-side support), it would be in the HTTP-REFERER field. That field is not
more secure than the others, but when a Web application sends cookies to the
user’s browser, it’s a signal that something interesting is being
stored,3 as shown in Figure
4-14.
Utilizing the HTTP-REFERER is less likely to alert an attacker to its use
because it is sent with every page request. Some proxies, however, may strip
this information as a privacy precaution, so applications may not be able to
rely on it. Manually typing a URL in the address bar also prevents it from being
sent.
To protect against the risk of users tampering with data that has to be
stored on the client, consider encrypting the data with a well-known standard
and restrict storing the encryption/decryption keys on the server. (Be extremely
suspicious of roll-your-own cryptography. We talk about attacking crypto in
Chapter 8, "Authentication.")
Attack 10: Session Hijacking
Of all the state-based attacks that have been discussed thus far, session
hijacking has the most exposure in the Web development literature. The reason
for this is simple: You can use session management to solve a lot of the
problems of storing state in a Web application. The issue is that if you do it
incorrectly, it is open to attack.
Session management works by each user having a unique identifier that travels
with him during his use of a Web site. This generally occurs with the server
issuing a number to each new user on the initial home page of the site. All
further requests would include this identifier so that Web applications can
distinctly identify users and store their associated state information on the
server.
You can use several methods to break session management by swapping the
session identifier of one user with the session identifier of another user. The
methods are as follows:
- Modifying data randomly, hoping to become another user
- Figuring out the sequence of unique identifiers that the site
uses
- "Fixing" the session identifier of another user
Session identifiers are presented to the server as hidden fields, appended to
URLs, or stored in cookies. Storing the session identifier in a cookie and then
passing it to the server as each page is loaded is the most common. Session
hijacking is the culmination of all the attacks that have been presented in this
section.
When to Apply This Attack
The
most
obvious
way
of identifying
when
to apply
this
attack
is when
you
see
a cookie
sent
to the
browser.
The
cookie
must
contain
some
session
identifier.
A recent
survey
of Web
sites
showed
that
the
following
are
the
most
common
names
for
session
cookies:
- ASPSESSIONID
- JSESSIONID
- PHPSESSID
- CFID
- CFTOKEN
However,
treat
with
suspicion
any
cookie
that
uses
the
moniker "ID" or
looks
like
a unique
number.
When
cookies
are
unavailable
(some
users
disable
them),
you
can
append
an identifier
as a
CGI
parameter
or insert
it (munge
it)
into
the
page
URL
as Amazon.com
does.
How to Perform This Attack
The attacker’s objective in session hijacking is to masquerade as
another legitimate user by using that person’s identifying
credentials—the session identifier. The most common way of achieving this
is to steal that user’s session identifier by various means. (The
cross-site scripting attack is often associated with this goal, although
monitoring network traffic is another avenue.) However, as we shall see later,
it is also possible to "give" a user a compromised session.
Poorly implemented session handlers open the door to guessing previous or
future session identifiers. The most obvious is where IDs are allocated
sequentially, so the next person to visit the application will get the n+1 (or
some other identifiable pattern) value. Therefore, we should first try to gather
a number of session identifiers and see if we can find a pattern that will allow
us to predict what identifiers a Web site will use for future and past
visitors.
If we know or can figure out a session identifier, we can replace the value
of the session variable (hidden field, CGI parameter, or cookie) with another
valid one and then request a page again. However, with or without this
knowledge, it may be necessary to try the attack several times as legitimate
users log into and out of the Web site.
Some Web applications may provide helpful error messages when an invalid
session is requested, which helps with this attack, but the main clue that the
attack is successful is when personalized information of another user appears,
as in Figure
4-16.
Another form of attacking session management is called session
fixation. It is subtly different from session hijacking because
hijacking suggests that there is something in-place to take. Session
fixation occurs when the session ID is stolen before a legitimate user ever gets
it. The attacker can then take the session from the legitimate user any time it
is advantageous to do so.
As Figure
4-17 shows, this attack works by an attacker either generating a
compromised session, or, depending on the session management mechanism,
providing a link to the Web site with the session identifier already provided in
the URL. The unsuspecting user logs in or clicks on the link and uses the Web
application. Because the session is a valid one, the legitimate user
doesn’t notice a difference. However, the critical problem is that the
attacker now knows the legitimate user’s session identifier and can assume
his identity.
The most probable targets for session fixation attacks are Webmail-type
systems. This is because taking over a user’s shopping cart doesn’t
really achieve anything (an attacker is unlikely to want to pay for someone
else’s goods!), but being able to read or send another user’s e-mail
after he has finished is a conceivable attack.
How to Protect Against This Attack
Session management is a necessity of Web applications, and if done correctly,
it can be an effective protection mechanism against a number of attacks,
including session hijacking. That’s why it’s typical for Web
developers to utilize sessions, despite their security implications.
Here’s some advice about doing it right.
Protection of a session needs to focus on the unique session identifier
because it is the only thing that distinguishes users. If the session ID is
compromised, attackers can impersonate other users on the system.
The first thing is to ensure that the sequence of identification numbers
issued by the session management system is unpredictable; otherwise, it’s
trivial to hijack another user’s session. Having a large number of
possible session IDs (meaning that they should be very long) means that there
are a lot more permutations for an attacker to try.
Developers also need to pay attention to the random qualities (those that are
nonsequential and hard to guess) of chosen individual IDs so that an attacker
cannot easily determine the algorithm used to generate the session IDs.
Taking
care
to generate
good
session
IDs
is just
the
beginning.
After
you've
generated
the
ID,
you
must
protect
it,
which
is a
concept
called session
management.
Good
session
management
consists
of the
following:
-
Using
cookies for storing session values.
Cookies
are
generally
more
difficult
to
modify
than
hidden
fields
or
CGI
parameters.
You
can
protect
them
by
using
mechanisms
like
setting
the
secure
flag
(so
they
cannot
be "sniffed" unencrypted
on
the
network).
In
addition,
you
can
restrict
cookies
to
a
particular
site
or
even
a
section
of
a
site
(using
the
path
attribute
of
the
cookie4),
or
set
them
to
expire
automatically.
-
Not
allowing users to choose their
own session identifiers.
Some
session
management
systems
allow
users
to
reactivate
their
session
if
they
have
a
valid
session
ID
but
it
has
been
expired.
There
is
no
good
reason
why
an
existing
session
should
be
reactivated
because
a
new
session
can
be
created
with
a
different
session
identifier
but
the
same
stored
state.
If
an
attacker
discovers
that
session
identifiers
are
being
reused,
he
can
gather
a
number
of
valid
ones
and
have
an
immediate
advantage
in
a
session
fixation
attack.
-
Ensuring
that each user gets a "clean" session
identifier number with each visit
and revisits to your site.
Users
should
get
a
new
session
number
each
time
they
visit
your
site,
because
that
makes
the
attacker's
job
of
giving
them
a
compromised
ID
irrelevant.
You
can
check
this
by
comparing
the
referring
page
against
the
URL
of
the
site.
If
they
are
different,
you
should
create
a
new
session
identifier.
However,
a
downside
to
this
is
that
it
might
break
the "remember
me" and "single-click
shopping" that
some
e-commerce
sites
use.
-
Time-out
session identifiers so someone
cannot reuse them after a predetermined
period of time.
Storing
session variables on the server
allows the Web application to
keep track of what sessions have
been created and when. If no one
has used a session for a specified
period (based on user activity
or a predefined time), you should
expire it. This gives the attacker
a smaller window of opportunity
to guess (or brute force) valid
session identifiers.
-
Allowing
users to log out and clear their
session.
When
a
user
logs
out,
this
action
should
invalidate
identification
numbers
from
both
the
client
and
the
server.
Not
only
should
it
clear
the
current
sessions,
but
it
should
clear
all
other
sessions
that
the
users
may
have
initiated
but
have
failed
to
log
out
of
because
of
forgetfulness
(browsing
away
from
the
site)
or
some
other
issue
like
server
failure.
-
Utilizing
the HTTP referer field to identify
multiple clients browsing with
the same ID.
If
the
Web
application
can "track" users
through
the
site
and
has
clear
paths
of
browsing
that
users
follow,
it's
possible
to
discover
situations
where
two
or
more
people
are
using
the
same
identifier.
The
basic
idea
is
to
know
the
correct
page
sequence
of
the
site.
If
a
request
for
a
page
that
should
not
be
accessible
is
received,
then
either
a
URL-jumping
attack
is
in
progress,
or
another
user
is
using
the
same
session
identifier
and
is
out
of
step
with
the
original
user.
In
both
situations,
the
session
identifier
should
be
invalidated.
-
Ensuring
that session cookies are sent
only over secure channels to prevent
them from being captured in transit.
You
wouldn't
want
credit
card
numbers
being
sent
in
clear
text
across
the
network,
and
because
session
identifiers
are
indirect
references
to
users' information,
you
should
protect
them
equally.
Because
cookies
are
sent
with
every
request
matching
a
specified
domain
and
path,
it's
easy
for
them
to
be
inadvertently
sent
over
a
nonencrypted
channel
where
an
attacker
may
be
listening.
Therefore,
you
should
set
the
secure
flag
for
all
session
identifier
cookies
to
ensure
that
they
are
sent
only
over
HTTPS.
Even
with
these
precautions,
there's
the
possibility
of an
attacker
discovering
a current
session
ID by "stealing" a
cookie
through
cross-site
scripting,
so protecting
against
that
attack
is a
crucial
facet
of protecting
against
this
one.
Cross-site
scripting
is a
topic
for
another
chapter.
References
- http://www.parosproxy.org
- http://www.securityspace.com/
- http://www.dutchduck.com/help/cookiesexplorer/faq/
- http://www.acros.si/papers/session_fixation.pdf
|