Tims Servlet Tutorial

Tutorial Home

  1. What are servlets ?
  2. The Hello World Servlet
  3. Running Servlets
  4. Reading Form Data
  5. Servlet Configuration
  6. Client Side Form Validation
  7. Cookies
  8. Sessions
  9. Authentication
  10. Dynamic Images
  11. Design, Testing, Security
  12. Servlets and Apache
  13. Using Servlets in SOCS

Design, Testing and Security Issues


Listed below are a number of issues which need to be thought about when writing a servlet. Issues such as URL portability and Security apply to any piece of software designed to be run on a webserver.

Multiple Threading

Every java servlet must take account of the fact that there could be multiple threads of execution running that servlet. Simple servlets, such as those described in this tutorial are unlikely to have problems, but with more complex servlets these issues could become important.

The best way is to design your code to be Thread-safe. The basic rule to making a class thread-safe is too avoid using global variables in your classes. Every variable which could possibly have it's state altered by a thread running through the servlet must be made local to the method. The only global variables should be for configuration data set up in the init() method of the servlet.

In some cases you may have to use utility classes which are not thread-safe, potentially causing problems. The Java Servlet API does, however provide a simple solution to this problem, in the form of an Interface called SingleThreadModel. The SingleThreadModel interface is an empty interface which can be used to mark a servlet that isn't thread-safe. A servlet marked with this interface will only allow one thread to be executing on any single instance of that servlet at any one time. However, using this interface is a great way of killing the performance of a servlet based system, so it should be avoided where possible.


HTML Generation and Testing

When writing a servlet you may want to give some thought the way that any HTML you may pass back to the servlet is generated. Some possible methods are :

  1. Embed the HTML directly into the program code. This is simple and effective, but it can be difficult to work with if the pages being generated are complicated.
  2. Use the javax.swing.text.html classes to build HTML documents with Java code
  3. Use template files stored separately from the Java code. These template files can be loaded by the servlet and the modified as required before being passed to the webbrowser.

You should also give very careful thought to the testing of any HTML/Javascript in your pages. Every web browser currently handles and renders web pages in a slightly different way. In particular, most browsers are 'error tolerant' to a certain extent, eg if you make a mistake in your HTML/Javascript, instead of doing nothing, the browser will make a 'this is what I think you want guess' based on the code that is there. Unfortunately, different browsers make different assumptions, so if you have bad code in your pages it might work differently or not at all in a different browser to the one you originally tested with. As a rough guide all web pages should be tested in two distinctly different browsers (not simply two different versions of the same browser), eg Netscape 4.x and Internet Explorer would be a good combination. Netscape 4.x is very error-intolerant whilst IE is very error tolerant, so this is a particularly good combination.


Servlet URL Portability

You might find it useful to make you're servlet URL portable. If you 'hard code' the URL of the servlet into any of the pages used to communicate with the servlet, this will make it much more difficult for you to move the servlet between servers, which may put servlets in different locations, without having to re-write parts of the code. The servlet can read it's current location on the webserver by calling the getRequestURI() method of the HttpServletRequest class and then insert this into all of the dynamically generated pages where necessary.


Sample code showing a modification of the myNameServlet which provides dynamic generation of the initial form, making it URL independent.

 public void doPost(HttpServletRequest req, HttpServletResponse res)
   throws ServletException, IOException
 {
  String[] param=req.getParameterValues("yourname");
  res.setContentType("text/html");
  PrintWriter out=res.getWriter();

  //*****If param is not null display the 'hello' message.
  //      Otherwise give the user a form*****
  if (param!=null)
  {
   out.println("<HTML>\n"+
    "<HEAD><TITLE>My Name Servlet Response</TITLE></HEAD>\n"+
    "<BODY>\n"+
    "<CENTER><BR><B>");
   out.println("Hello "+param[0]);
   out.println("</B></CENTER>\n</BODY>\n</HTML>");
  }
  else
  {
   out.println("<HTML>");
   out.println("<HEAD><TITLE>My Name Servlet Demonstration</TITLE></HEAD>");
   out.println("<BODY>");
   out.println("<CENTER>");
   out.println("<FORM ACTION='"+req.getRequestURI()+"' METHOD=POST>");
   out.println("Please Enter your name <INPUT TYPE=TEXT NAME='yourname'>");
   out.println("<INPUT TYPE=SUBMIT VALUE=Submit>");
   out.println("</FORM>");
   out.println("</CENTER>");
   out.println("</BODY>");
   out.println("</HTML>");
  }

  out.close();
 }

Click here to try the modified version of the MyNameServlet, with URL portability.

URL portability is especially handy if you're testing on a heavily loaded multi user machine, you may find that the port you've been using for the servletrunner (or similar) is already in use. With hard-coded URL's in your pages, you may have to change every single page before you can continue working with a new port number for the servletrunner. If you make the URL's portable, this will not be necessary. It is also makes life a lot easier when moving from a test setup to a production web server.

You should also avoid using localhost/127.0.0.1 in any of your URLs if those pages are intended form anything other than private testing. Ideally, you shouldn't need to put any 'http://' references into your pages, as long as the servlet is on the same server as the web pages that refer to it, a relative URL references are more than adequate. eg <FORM ACTION="/servlets/demoServlets.MyNameServlet">.

Security

Every servlet you put your webserver could (potentially) be exploited to damage your computer systems. All good servlet engines (such as Apache JServ or Tomcat) have high levels of security built into them, however this security is useless if your servlet is not written with security in mind.

An example of what not to do : I once had a student writing a web interface to a database, this interface involved an applet which communicated with a servlet which communicated with a database. All of the SQL commands for connecting to the database were generated by the applet and passed to the servlet, which executed them and returned the results. The problem was that the servlet allowed any SQL command to be executed unchecked, so a malicious person could have written a new applet which sent in SQL commands to (for example) delete the entire database !

Their are two possible solutions to this :-

  1. Get the servlet to check the SQL and reject any malicious statements.
  2. Move all the SQL into the servlet and have the applet request the relevant functions.

Method one has a serious problem, it is not fail-safe and potentially very complicated, however good your checking procedures are, their is always a risk that a malicious statement would slip through. Method two is much safer, their is absolutely no way that a malicious user could perform any task other than the ones you have allowed, ie everything that is not specifically allowed is disallowed. Unfortunately, their may be cases where you have to have validity checking on the submitted request, when this occurs, ensure that you rigorously test all possibilities. Try to deliberately break the security by passing requests to the servlet which would not normally be allowed by the interface and which could cause damage if they were allowed.

The lesson to draw from this is that whilst you will write an interface that controls the way in which a normal user can access your system using HTML and Javascript, the networked nature of servlet programming means that there is nothing to stop somebody bypassing your interface and feeding data directly to your servlet. This means that your servlet must be able to detect and reject bad data, in addition to any checks/restrictions which might be imposed by the design of the HTML/Javscript. The classic way of hacking a system is to bypass the normal 'interfaces' and try to feed bad data directly into the service that the machine provides.


<< Previous Page | Next Page >>




Tims Home Page       |       Page last modified : 19 May 2003