Just a little under 2 years ago, I became more aware of security as an important part of implementing a complete system. I know that many simply rely on the role based ACL-paradigm of the Sun Servlet spec. they’re using. Others may build their own Filter-based system. If keeping out non-authenticated and /or non-authorized users is your goal, this will suffice.
Some go further and use a proper framework to do this. One of the more popular, and in my opinion – better frameworks is Acegi. Relying on the Spring frameworks core concepts, it’s fairly lightweight, and non-intrusive. This is partly why it’s now Spring sub-project. Unless you are a fan of recreating the wheel, this is obviously a step up.
Assume basic security is achieved: a non-authenticated or non-authorized user cannot gain access to protected resources on your system. Great, but can’t stop there? In the summer of 2005, I was asked (told) to attend a security conference in Baltimore, MD. It wasn’t as bad as I expected it to be: spent 3 days at an old college buddies home, saw places I hadn’t seen in about a decade. Oh, and the conference wasn’t half bad – I learned quite a bit.
The most important lesson was that authenticated and authorized users can still be malicious. One of the better presenters recalled a situation in which a C-level exec at a company was using an inventory site, along with his competitors. This exec realized that by changing his user-id in the query string from “1” to “3” (another reason why you should use a GUID generator), he could get access to a competitor’s information. Although this was a read-only inventory view, the exec was able to make decisions at his firm based directly on this information — most would call this an unfair advantage. When this came to light, obviously the exec and his firm faced some issues, but this destroyed the integrity of the inventory site. All this to say, even with your ‘trusted’ users: Trust, but Verify.
Even if located in a safe community, an apartment building will have a locked front door. This is simply an attempt to authenticate people coming into the building via a door key (ROLE_RENTER). However, just because you enter a building doesn’t mean you are authorized to every corner of that building. In order to go to the basement or roof, you need a special key that only the superintendent has (ROLE_SUPER). To enter apartment #3, you will need the key for that apartment. Roles aren’t enough here — you need to white-list a set of keys that only open the lock on apartment #3.
Look at your own code, some of us simply assume if the role A can’t see data made only for role B, we’re good to go. No, we’re not (see example above). This requires white-list restrictions at the service and/or domain level. I suggest the verification should take place nearest the thing that needs protection. Verify domain access in your persistence/dao layer, and verify actions at the service layer.
Some (me) of have made the mistake of relying solely on Hibernate’s Filter feature for access security. This is based on a false assumption: if the user can’t see an item, they can’t edit it. Those filters simply provide views of existing data without having to actually define the view in your schema. These filters do not get applied to Hibernate Session
load(…) calls. Hence, if a user specifies a valid object id, even though they could not see it in their filtered view, they can access it via a direct load. Abandoning get and load in your daos is removing your nose in spite of your face: you’d lose some of the benefit of secondary cache retrieval. So then what?
Well, if you aren’t already an Acegi user, you should consider it. Acegi comes with reasonable documentation and good examples on how to implement JDBC-based ACL security for both your services and domain objects. However, if you use Hibernate, you’ll need to provide your own implementation for some things (ACL-entry mapping and retrieval). More on that in a future post.