JAX-RS and RESTful Security
The use of HTTP, as the driving force of SOA can never be exemplified enough. In terms of the usefulness of SOA, I think that RESTful SOA is a no brainer, has some great uses, and I've always been confused at why people adopted SOAP nothingness. Or, should I say, SOAP wrappers that achieve nothing. RESTfulness, on it's basic level, having no required integrated security, is great for
- public information
- lookups of information that should be readily available for many systems, but does not contain user's private information (without a proper authentication/authorization model in place), etc
- systems not requiring proper/secure authentication and authorization
From a private personal data and security perspective (not that I'm an expert on security, by any means), the RESTful method of SOA really doesn't define much in the way of security. After all, any authentication method, unless it's directly or indirectly tied to the front end user's credentials, and also propagating those credentials to the back end REST service, with stateful authentication, is not adequate security. Having a certificate for example, is great to prevent sniffers, but not hackers that have compromised a client web server system.
Keep in mind, that even in the case of doing proper authentication, using user principals/credentials propagated all the way to the back end service (and only on the first access), a rooted hacker could get the passwords of a few accounts, simply by setting up a proxy with the front end ssl cert, but at least they haven't compromised EVERYONE'S account.Consider a HYPOTHETICAL scenario. Amazon, unbeknown to everyone, has been using SOA, in a RESTful manner, for years, as the back end of their web servers. They use it for accessing customer information, making changes to customers accounts, storing and retrieving various bits of personal information, etc. The method of authentication from the front end web server, to the SOA server, is HTTP basic, or SSL client certificates, or a combination thereof. The credentials and client certificate are of course stored on the front end server. Suddenly, their front end web server is hacked, because there's a security glitch of some sort. The hacker actually gets root access; implicitly having access to the client certificate files, as well as the SOA HTTP basic auth username/password. Now the hacker has programmatic access to the SOA servers on the back end, immediately and without much effort, including query/update/delete privileges on ANY user account. Unless a RESTful developer is up to doing a lot of extra work, developing their own authentication, authorization, and stateful framework for RESTful, or RESTful v2.0 comes up with something, there's not much hope for system security in a scenario like this.
There's a few solutions to this problem that I can think of off the top of my head.
- Use HTTP basic auth, or some other method that keeps passing the credentials on each HTTP request, on the front end, and have those propagated to the back-end SOA services as well, and then adopting the stateful method discussed in #2. The problem with this is that it's a little vulnerable for currently authenticated users; if a hacker gets root, they can also obtain username/passwords of users that are currently authenticated, in addition to those performing new authentications.
- Create an authentication caching mechanism on the RESTful backend services, which only stores the username, the authenticated state, and a token. One method, when using HTTP as the protocol, is to simply use the cookie addition to HTTP. This would of course require that your client also support it.
- The initial authentication information is sent from the browser, to the DMZ web server, which forwards it to the RESTful service, and so on and so forth.
- The token is generated by the far most back end, and propagated forward to the DMZ web server.
- On subsequent requests, the token is passed from the DMZ web server, to the RESTful services, as far back as needed, WITHOUT including private information such as username/password.
- No account querying or modification is allowed without a valid token, and perhaps also including IP, and various other information.
- After the first request, all account create/update/delete queries will only be tied to the user that is connected to the token, which only the farthest back server knows about.
- Use a protocol/framework that is already stateful. Perhaps EJB, or RMI, may be in order, if one is using Java.
- Only ONE RMI object should be allowed to instantiate any objects that have access to private user data, and that object should be the one providing authentication.RMI provides an easy to use stateful mechanism for calling services on the backend. The state is maintained entirely automatically by the RMI subsystem. It does not, however, have an integrated authentication or authorization system. Such systems are trivial to develop for RMI, as it keeps state for you, and gives you full access to OOD methods.
- EJB provides a stateful mechanism, with authentication and authorization, all handled by mere server configurations. Unlike RMI, there is no need to develop your own authentication/authorization system. In fact, the authentication/authorization of EJB can be propagated down a long chain of EJB servers, including the principals and credentials of the user. As far as my reading of the EJB3 specification goes, the credentials are not cached, just propagated on the first call of a stateful session bean, and every call on a stateless bean, to establish the state. In the case of OpenEJB, I tested this by changing the user's password on the standalone OpenEJB server, but not on the front end tomcat server. It worked great, and complained that the user's password was bad. Ultimately, what I would like to see here, is the ability to have EJB only authenticate using the back most EJB server, and that authentication gets propagated to the front end. That way, the security layer is initialized as far back from the DMZ as absolutely possible. Requiring that the DMZ machine has access to the authentication server as well, is a bit poor. Ultimately what we want is the authentication server (say LDAP) is completely inaccessible from anything but the farthest back EJB server. I believe the EJB3 specification indicates that this is possible, but I have yet to investigate how to do it with OpenEJB.
A scenario, where security may not be as important, is when the web services are for returning public data, such as postal/zip codes, towns, countries, provinces, product listings, etc. If someone hacks the web front end in one of those scenarios, and wants to do queries on what the zip code is in some town in Texas, the level of breach is not as significant as it is when they have access to everyone's private information. In cases like this, RESTful web services are really great, and very much simple. But, when good security is required, for ensuring the privacy of user information, writing RESTful web services becomes time consuming, and error prone, and a little negligent if the developer does not integrate proper security.
Java EE 6 is supposed to support integration of JAX-RS web services, as EJBs. I'm not sure whether the JAX-RS service would then inherit proper security or not.The whole point of this post, is NOT to discourage the use of JAX-RS, or any RESTful framework, but to think about what you're using a technology for (such as RESTful), and whether it is the best fit for the problem at hand. Without a lot of work, proper web service security for private user information, using most SOA methods (SOAP, RESTful, JAX-RS, JAX-WS, etc) is a pain. And, if you're looking into developing an enterprise level application, with a need to safe-guard private user information, it may be worth looking at other technologies, such as EJB, RMI, etc. After all, they provide a lot more other useful features, such as statefulness.
Granted, if someone gets root on your DMZ, you're in big trouble anyhow, ESPECIALLY if you don't know about it. But, at least you save potentially THOUSANDS of users from having their accounts compromised. Consider a University, which has tens of thousands of students. If the authentication is not tied directly to the principals/credentials of each user, or it is being done by simple basic/auth, or even SSL client certificates, the hacker who got root on your machine can mess with, or query, all tens of thousands of accounts. If you put this three-tier mechanism in place, the only people's accounts they can get access to, are those for whom they have intercepted their passwords. Which, hopefully, will only be a handful.
February 11th, 2010 - 02:02
I just realized. There is another solution to this problem of security, and it may be much simpler to implement than I had originally thought. Someone could write a filter that does what they need, in the J2EE container, or in the jax-rs implementation they chose, and assuming the client code of that particular implementation supports it, a client filter as well. Then, keep the authentication state only, via a cookie perhaps.
It would be nice if this was all agreed upon in the jax-rs spec, or perhaps an HTTP specific jax-rs sub-spec. Although, jax-rs implementations are REQUIRED to support cookies.