Using HttpUnit for Security Testing
|
Andy Meneely and Laurie Williams [Contact Authors] |
| 1.0 | What is HttpUnit? |
| 2.0 | Installing HttpUnit in iTrust |
| 3.0 | Using HttpUnit |
| 4.0 | Fixing the Error Message XSS |
| 5.0 | Some Handy HttpUnit Tests |
| 6.0 | Exercise |
| 7.0 | Resources |
|
HttpUnit is a Java API for interacting with websites. Acting as a browser, HttpUnit enables a programmer to automate testing on a website by sending HTTP requests, returning the responses, and parsing the HTML that is returned. HttpUnit also supports HTTP headers, cookies, Javascript execution, DOM, and many other features used in web development. Although HttpUnit is typically used as a utility for JUnit tests (hence its name), it can actually be used for any automated interaction over HTTP - test or not. For our purposes, we will be using HttpUnit for security testing - specifically, penetration testing - of our J2EE web application, iTrust. While much of our penetration testing can be done with JUnit interacting directly with our Java code, many vulnerabilities lie in our as-of-yet untested JSPs. In this tutorial, we will write a test for a particularly bad Cross-Site Scripting (XSS) vulnerability in iTrust that lies in a JSP. One could, however, use HttpUnit to test almost any kind of web application vulnerability, such as SQL Injection or Denial of Service. |
|
HttpUnit consists of a number of Java jars files used for various purposes. This section will demonstrate how to add new JAR files to the iTrust classpath in Eclipse WTP.
|
|
HttpUnit uses the following key classes:
A typical HttpUnit session might look like the the following code. Can you see what it does?
WebConversation webConversation = new WebConversation();
WebResponse loginResponse = webConversation.getResponse("http://localhost:8080/iTrust");
assertEquals("iTrust Login", loginResponse.getTitle());
WebResponse homePage = loginResponse.getLinkWith("HCP").click();
assertEquals("iTrust - HCP Home", homePage.getTitle());
The code first requests iTrust, clicks on the first link with "HCP" as a substring (happens to be the testing-only link above login), and goes to the HCP homepage. Copy this into your own unit test and run it (be sure to have Tomcat running!) Alternatively, you could use the actual form submission by obtaining the first (and, in this case, only) form from the response, setting the parameters, and submitting. The following snippet will do the trick:
WebConversation webConversation = new WebConversation();
WebResponse loginResponse = webConversation.getResponse("http://localhost:8080/iTrust");
assertEquals("iTrust Login", loginResponse.getTitle());
loginResponse.getForms()[0].setParameter("j_username", "9000000000");
loginResponse.getForms()[0].setParameter("j_password", "pw");
WebResponse homePage = loginResponse.getForms()[0].submit();
assertEquals("iTrust - HCP Home", homePage.getTitle());
A few comments worthy of note:
|
|
iTrust has a particularly bad Cross-Site Scripting (XSS) vulnerability in one of its header files that allows an attacker to craft a URL which could result in an execution of Javascript in a client's browser. The exploit uses the "error" field used throughout the application to report an error at the top of a page. If you have iTrust running on your local system, you can test this out by going to the link and log in in as an HCP: http://localhost:8080/iTrust/auth/hcp/hcpHome.jsp?error=<script>alert('XSS');</script> First, let's write a test case that will initially fail when it's run. Using a similar approach as our example above, use the following as your unit test:
public class ErrorXSS extends TestCase {
private static final String XSS_EXPLOIT = "<script>alert('XSS');</script>";
private static final String ESCAPED_XSS_EXPLOIT = "<script>alert('XSS');</script>";
public void testXSSInErrorMessage() throws Exception {
WebConversation webConversation = new WebConversation();
WebResponse loginResponse = webConversation
.getResponse("http://localhost:8080/iTrust/auth/hcp/hcpHome.jsp?error="
+ XSS_EXPLOIT);
assertEquals("iTrust Login", loginResponse.getTitle());
WebResponse homePage = loginResponse.getLinkWith("HCP").click();
assertEquals("iTrust - HCP Home", homePage.getTitle());
assertFalse("Should not contain an XSS exploit", homePage.getText()
.contains(XSS_EXPLOIT));
assertTrue("Should contain the escaped version of the exploit",
homePage.getText().contains(ESCAPED_XSS_EXPLOIT));
}
}
If you run this code as a unit test, you should
get a red bar with the comment: Now to fix the vulnerability. For this tutorial,
we will simply escape the characters passed to the Open up the file
if (request.getParameter("error") != null) {
%>
<span class=error> <%=request.getParameter("error")%> </span>
<%
}
Change the middle line to use the already-written
HTMLEncoder method in the
HtmlEncoder.encode(request.getParameter("error"))
Green bar! |
|
You now have all of the tools you need to execute JUnit test via making HTTP requests using HttpUnit. Below are some other helpful HttpUnit code snippets that might help for security testing. They are not meant to be complete, so please adapt to taste. The following helps for expecting an authorization (403) error.
try {
new WebConversation().getResponse("URL YOU SHOULDN'T GET TO!");
fail("exception should have been thrown");
} catch (HttpException e) {
assertEquals(403, e.getResponseCode());
}
HttpUnit also parses tables - however, it handles
nested tables rather peculiarly. I reccommend using
WebConversation webConversation = new WebConversation();
WebResponse loginResponse = webConversation
.getResponse("http://localhost:8080/iTrust/auth/hcp-uap/editBasicHealth.jsp?pid=2");
WebResponse basicHealth = loginResponse.getLinkWith("HCP").click();
WebTable table = basicHealth.getTableStartingWithPrefix("Basic Health");
assertEquals("Smokes?", table.getCellAsText(1, 2));
|
| For future assignments, you will be responsible for writing automated tests using HttpUnit that test security vulnerabilities in iTrust. Be sure to organize your unit tests logically and to comment your security based on the particular exploit. |
| HttpUnit |