Steve Levine

Archive for the ‘REST’ tag

Simple Security for HTTP Based RESTful Services (Part 2)

with 2 comments

In part one of this series, we examined one potential solution that turned out to be not so good. In this post lets try to find a solution using the same design, but a better implementation.

To recap, we decided to use the simplest solution which is to add a security hash to each service call. The first approach we tried was adding the security hash to the XML payload of each service call. The conclusion was that approach was not very elegant, and actually quite ugly.

Let us now discuss a more elegant solution. Keeping the same parameters in place, namely, we want to pass the hash along with each service request, where can we place it where it will not cause the implementation to be ugly? Why don’t we try by add the Hash as a field in the Http header?

The request would look like:

PUT http://blah.com/services/someEntity/226 HTTP/1.1
Accept: text/xml
Content-Type: text/xml
User-Agent: Jakarta Commons-HttpClient/3.1
Host: somehost:port
Hash: 53b383c67a03d23a38b6f52f4a732553
Content-Length: 380
<someEntity>
	<fieldOne> fieldOne </fieldOne>
	<fieldTwo> fieldTwo </fieldTwo>
</someEntity>

As you can see, the hash has been added to the Http header (line 6). To verify the hash, we need to do create a Servlet Filter that verifies the Hash.

A very simple filter would look like:

public class VerifyHashFilter implements Filter {
   public void doFilter(ServletRequest request,
			ServletResponse response,FilterChain chain)
	 		throws IOException, ServletException {
     if(((HttpServletRequest)request).getHeader("HASH").equals("12345"))
        chain.doFilter(request,response)
     else
        ((HttpServletResponse)response).setStatus(401);
   }
}

Then our service code implementation would change to:

@Path("/services")
public class SomeEntityServiceImpl {

    @PUT
    @Path("/someEntity/{id}")
    @Consumes("text/xml")
    public void updateSomeEntity(SomeEntity entity,
				@PathParam("id") int id) {
	dao.saveOrupdate(entity)
    }
}

To test our service, we can use curl:

$ curl -i  -H 'HASH:12345' http://localhost:9095/rest-test
HTTP/1.1 200 OK
Content-Type: application/xml
Content-Length: 71
Server: Jetty(6.1.14)

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<someEntity>
	<fieldOne>fieldOne</fieldOne>
	<fieldTwo>fieldTwo</fieldTwo>
</someEntity>

And the negative test:

$ curl -i  -H 'HASH:54321' http://localhost:9095/rest-test
HTTP/1.1 401 Unauthorized
Content-Length: 0
Server: Jetty(6.1.14)

As you can see, the implementation code is much cleaner and reusable now. The service code can be called from anywhere within the application without having to worry about a security hash. It is safe to assume that if the code makes it as far as the service, it passed through the security filter thus making the request authorized. Having that assumption as part of the design allows you to write much more generic and reusable code.

Please keep in mind this concept is nothing new, as this solution is an over simplification of how the Spring Security module works. The value in this solution is it doesn’t have dependencies on any external frameworks. When designing this solution, that was one of the determining factors.

Next time you need to implement a quick authorization mechanism for your REST service, make sure you keep the Http header along with a Servlet filter in mind.

This entry was posted by Steve on Tuesday, December 16th, 2008 at 6:51 pm and is filed under: , , . You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

Simple Security for HTTP Based RESTful Services (Part 1)

without comments

This is going to be the first in a series of posts discussing potential ways of securing bi-directional RESTful based HTTP services. For this series we are going to make the requirements quite simple, namely, “secure” simply means the caller of the service is authorized to invoke it. Lets assume that this solution is being deployed along with a simple IP addresses restriction mechanism. Since IP address’s can easily be spoofed, this solution is the next level of defense to ensure the identity of the caller.

There are many different potential solutions to this problem, but for this series, we are going to focus on the simplest solution which is to add a security hash to each service call. This post assumes you understand how to secure B2B communications with the use of a security hash. If you need a refresher, please refer to this post on the subject.

Since we know the design for securing our communications, we need to decide on an implementation. The first potential implementation we are going to examine is adding a “security hash” to the XML payload for each service call.

The embellished XML payload would look like:

<someEntity>
	<hash>4723af11bef05fc6207bd22cd163d9db</hash>
	<fieldOne> ... </fieldOne>
	<fieldTwo> ... </fieldTwo>
</someEntity>

with the “hash” field (line 2) representing the security hash.

The interface of the SomeEntity service, would look like:

public interface SomeEntityService {
	public void updateSomeEntity(SomeEntity entity, int id) throws SecurityException;
}

with an implementation that looks like:

@Path("/services")
public class SomeEntityServiceImpl {

    @PUT
    @Path("/someEntity/{id}")
    @Consumes("text/xml")
    public void updateSomeEntity(SomeEntity entity,
					@PathParam("id") int id)
						throws SecurityException {
		if (validateHash(entity))
			dao.saveOrupdate(entity)
		else
			throw new SecurityException("Not Authorized");
    }
}

With the actual HTTP Client call looking like:

PUT http://blah.com/services/someEntity/226 HTTP/1.1
Accept: text/xml
Content-Type: text/xml
User-Agent: Jakarta Commons-HttpClient/3.1
Host: somehost:port
Content-Length: 380
<someEntity>
	<hash>4723af11bef05fc6207bd22cd163d9db</hash>
	<fieldOne> fieldOne </fieldOne>
	<fieldTwo> fieldTwo </fieldTwo>
</someEntity>

There you have it, our first potential solution to the problem. We now need to examine if this solution is correct, and if it is, is it elegant?

First things first, is it correct? If you trace through the code, you can see that before the service makes a call to the DAO, it checks to verify the validity of the hash field (line 10). If the hash it is not valid, it will throw an Exception, which in turn would return a 401 to the user. It would not be possible for a client to access the DAO without having the proper hash as part of the XML Payload.

Even though this approach would perform as expected, it has two main issues, the first being it mixes concerns. What we mean by mixes concerns is it mixes business logic with security logic. This is a standard problem that applies to layered architectures. The main side effect of this problem is it makes the code very difficult to reuse. Lets me demonstrate this with a simple code fragment:

// Code in a Web Controller class somewhere
try {
	someEntitySvc.updateSomeEntity(entity);
} catch (SecurityException e) {
	// Nothing we can do... We don't have the hash???
}

As you can see from this simple example the implementation of the service is not generic enough to be usable by a Controller in the Web Tier. Firstly, even if the Web Tier knew about he hash, the code becomes polluted with Exception handling for an Exception that is not applicable to this client. Secondly, the Web Tier simply doesn’t have any knowledge of the hash, and putting logic here to generate the hash just to use the service would not make any sense from a design perspective.

The second issue with this approach is the fact that you can only apply it to Http methods that accept a payload. What about methods that do not accept a Payload, I.e., GET? To make this work for the GET method, we would have to pollute our GET method implementation with a @Consumes(“text/xml”) tag, which functionally would work, but from a API design perspective, it is quite ugly. As a consumer of a GET method, all you need to know is the id of the entity you wish to “get”. Adding an XML payload for “security” purposes is a bad and cumbersome design.

With all that being said, it looks like this is not the best solution to the problem. Stay tuned for part two of this series where we will discuss a more elegant approach to solving this problem.

This entry was posted by Steve on Saturday, November 29th, 2008 at 7:58 pm and is filed under: , , . You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

Fork me on GitHub Fork me on GitHub