NOTE: Sorry for "thinking out loud" here, but I usually enjoy reading other people's posts where they go through a design thought process in some area, so I thought it may be okay for me to do it here...
This topic obviously got me thinking :-) and I have determined that my recommendation to do a check in the action itself may be inconsistent with my complaint about redundent db calls if we were to develop a "pluggable" system where you would have security checking modules that are separate from your actions. The inconsistency is that doing the check in the action will often result in redundent db calls, too, making it no better than the "pluggable" solution in that respect. Here's an example: The action that shows a sales_report item (/viewSalesReportItem.do?sales_report_id=3) will probably load the sales_report object from the db to get the territory_id as part of the security check. But then it will likely delegate the loading and population of the SalesReportActionForm to some other class that will also make a call to the db to get the sales_report object from the db. Thus, we still end up with two calls to the db, when really only one is needed. One solution for this simple case is to have the action call the delegate to populate the action form, and then pick the territory out of the now-populated ActionForm to do the security check. That works in this simple case, but only if we are careful to ignore any territory_id info that came in with the request. This is not an issue for the other two cases, since in one of them the territory_id comes directly from the request (no db calls required) and in the other one, our db query will limit the results to data that we know the user is allowed to see. I think my problem here is that I like to do the security check up front in the action processing to avoid having to do any unecessary processing (i.e. stop the request as soon as you know the user doesn't have permission), and that leads to redundent calls. I am having a bit of trouble coming up with a specific example where the redundent db calls can't be avoided by doing the security check at the end of the action processing (right before forwarding to the JSP or other view component for display). But I imagine that some levels of indirection in the data model might result in not being able to get the territory_id for a security check. Here's an example that is slightly stilted, but perhaps reasonable: /viewOrder.do?orderId=10 Let's say that sales users should only be able to see orders in the territories that they have access to, but that the action to view an order is intended primarily for customers (who don't care what the territory is) rather than sales users. So, it might be that the call that the ViewOrder action makes to the business delegate to load the order information does not return the territory_id. In that case, the action would then have to do its own db calls to get a territory_id for the requested order to do a security check. Perhaps the most reasonable solution here would be to change the delegate and ActionForm (or DTO, etc. -- whatever the business delegate call returns or populates) to retrieve and contain the territory_id information so the check could be made at the end of the ViewOrder action. The security check would probably allow the request if the user is the customer that placed the order, or a user with the 'sales' role and the order is within a territory that have access to. But the security check is getting somewhat complicated now, and will probably be duplicated elsewhere if we put it directly in our ViewOrder action. So this lack of re-use and the potential for complicated security checking rules mixed in with action processing still leaves me wanting a way to separate it from the action itself. Implementing it separately also makes it easier to divide the work among multiple developers. But separating it out usually means redundent db calls. I can think of two possible solutions. One is new (in this thread), and the other one is a continuation of the "pluggable" security module design. Solution 1: Have the business layer do the security checking. This is somewhat appropriate anyway, since the security constraints are usually driven by business rules. Passing the username into the business layer would not be much of a problem, but you might want to develop a custom UserProfile class to encapsulate not only the username, but also other security info, such as what territories they have access to in our sales_report example. As a mechanism for communicating this information upward toward the view layer, the business layer could throw a custom SecurityException if an access violation is detected, and that could be caught by the action, the base action for your application, or even Struts itself for proper processing (i.e. to show the "access denied" page). This solution gets the security checks out of the actions, but moves it into the business layer, which might not be any better. But it does solve the problem of redundent calls to the db for the same info. Solution 2: I am still attracted to the idea of using a cache for db access that is limited to the scope of a single request. This would support the separate, pluggable security checking modules architecture without leading to redundent db calls. It wouldn't matter how many times different parts of the request processing chain want to load a certain object from the db, since it would be cached after the first load. Perhaps the cache could be attached to the thread (as a ThreadLocal variable), and it would be discarded by a filter at the end of processing for each request, as the server will be pooling the threads for use in processing other requests. (I have used a similar technique to limit the number of db connections used in processing a request to 1 to avoid "dining philosphers" deadlock issues.) If anyone has any knowledge or ideas about persistence layers (EJB, JDO, custom, etc.) that support this kind of thing, I would love to hear it. It would be great to be able to write the constraints declaratively, and the pluggable architecture backed by a peristence layer that avoid redundent calls seems to get us closer to that goal. It would be cool if you could write your security constraints in some simplified langauge (perhaps in some query language or an XML format) and then attach the constraint to a Struts action or a url-pattern. Simplifying the constraint language might improve communication between customers/users, business analysts, and developers, and would make it easier to change the constraints when the requirements change. And they would be easier to write in the first place. This would also open the door for tools vendors to make it even simpler still. I'd love to hear other ideas for implementing security requirements of this nature. What is your solution, and what are the advantages/disadvantages? If I am out of the loop on some product/project/standard/technology in this area, I'd like to hear about those, too. -Max ----- Original Message ----- From: "Max Cooper" <[EMAIL PROTECTED]> To: "Struts Users Mailing List" <[EMAIL PROTECTED]> Sent: Saturday, October 04, 2003 8:00 PM Subject: Re: Verifying integrity of URLs > The requirement to allow a given to user to see only a subset of the data in > a particular table is a relatively common one. For instance, in a sales > reporting application, you may have a table of total monthly sales for a > number of territories and a given user may only be allowed to view/edit one > territory or several but not all of the territory data. There may also be > users who aren't allowed to see any sales data at all. > > For instance, here is some sample data from our fictitious Sales_Report > table: > > id, territory_id, date, total_sales > 1, 1024, May-2003, $1000 > 2, 1024, Jun-2003, $1200 > 3, 1908, May-2003, $800 > 4, 2100, May-2003, $1300 > > To handle these requirements, you could use a combination of role-based and > programmatic security. You can use the role-based part to block access to > the sales reporting actions for users that aren't in sales. In other words, > a user would have to have the 'sales' role to view them. That takes care of > the users who can't see any sales data. > > Then you need to restrict users who do have the 'sales' role from seeing > data from territories they don't have access to. Consider these three > actions: > > /viewSalesReportItem.do?sales_report_id=3 > /viewSalesReport.do?territory_id=1024 > /viewAllMySalesReports.do > > For the first one, you can load the sales_report from the db and then get > the territory_id from it. Don't trust a territory_id coming in from the > request (e.g. > /viewSalesReportItem.do?sales_report_id=1908&territory_id=1024) because the > sales_report_id is really what determines what your app should show, and you > can see in my example URL that a user could just provide a territory_id that > they do have access to, but that isn't the right one for the sales_report > item they are requesting. That may seem obvious, but it is a common mistake > on update actions where the territory_id might be in the request as a POST > parameter in a hidden field. Users can fake POST parameters, too. Once you > have a trustworthy territory_id, check that the user has access to that > territory. There should be some join table in the db that indicates what > territories the current user has access to. If they don't have access, you > want to show some kind of "access denied" page. If it is okay for the access > denied page to be somewhat generic (and you aren't going to show the user > any links that would get them there, so I think this is okay), you can setup > a global forward to the access_denied page and have your Action return that. > > The second one is even easier, because it is the territory_id that directly > drives what the app is going to show. Again, just check that the user has > access to the requested territory, and return the "access_denied" global > forward if the check fails. On one app that I worked on, we put a > convenience method in our application's ActionBase class, which all of our > Actions used as their base class. It is a little clunky still, but our > convenience method would return the "access_denied" ActionForward if the > user did not have access, and null if they did have access. The code in each > action that used it looks something like this: > > ActionForward accessDenied = checkAccess(mapping, territoryId, request); > if (accessDenied != null) return accessDenied; > > We pass the mapping in so that the checkAccess method could get the > "access_denied" global forward. We pass the request in for two reasons. The > first is that the method needs to call request.getRemoteUser() to figure out > who the current user is. The second reason is that we have a utility class > that will cache the list of territories the user has access to in the > session, and it can get to the session from the request. > > The third action I listed up there (/viewAllMySalesReports.do) should show a > list of all sales_report rows that the user who requests it has access to. > In this case, you will want to adjust the db query to only return data that > the user can see. You could do that with a WHERE clause like "territory_id > IN (1024, 1908)" or perhaps better yet just join to the table in the db that > says what user has access to which territories. By limiting the results in > the db query, you avoid getting more data than you need and having to weed > through and discard the ones the user isn't supposed to see. > > > I have kicked around another idea where the programmatic security code would > not be in the action, but rather you would write a security module for a > given request and "plug it in" somewhere. For instance, for the > /viewSalesReportItem.do?sales_report_id=3 request, you would write a module > that would load the sales_report to get the territory_id and then determine > if the user has access to that territory. I was thinking of incorporating an > interface like this in SecurityFilter, where you might write a security > module that would allow or deny access and then register it with the filter > to be used for request URLs that match "/viewSalesReportItem.do". A > mechanism that allowed you to register a security module with a particular > (or a set of) Struts modules is also possible. The system would allow you to > register different modules with different actions, etc. The possible > advantages to using this kind of approach are that security code is > separated from the action itself (divide and conquer at a conceptual and/or > work assignment level) and that you could likely reuse a given module across > multiple actions (like the view and update actions for a sales_report, for > instance). > > However, there is a downside that I don't have a good solution for. Notice > how in this example that we had to load a sales_report from the db in the > security module to get the territory_id so that we could decide if the user > has access or not. In this case the action is going to load the sales_report > from the db again, which means we have more db calls than should really be > needed to process this request. One option to avoid the extra call would be > to have the security module save the sales_report object as a request > attribute for the action to retrieve later, but that couples the sales > module and the action too much, in my opinion. Another solution would be to > have some kind of generic, request-scoped cache of any db objects that have > been loaded. That would eliminate the coupling between the security module > and the action, since the action would just say "I want sales_report with > id=3" and it would either be retrieved from the cache or loaded from the db. > The action does not have to know or care if the object had already been > loaded from the db by the security module. But for that to work, you would > need to acquire or implement such a caching system (perhaps there are some > standard solutions, but I haven't researched it much), and then you would > also need to use it whenever you wanted to get something from the db. And > thus, I don't know of any good way to make this kind of thing work yet. > > You could use inheritance among your actions to get some of this benefit, > but that is less flexible than the "pluggable" architecture I was proposing > above. For instance, you could have an inheritance structure like this for > your actions: > > Action (Struts Action class) > ^ > | > MyAppBaseAction (base class for all of the Actions in your app) > ^ > | > SalesReportItemAction (base class that does security for SalesReportItem > actions) > ^ ^ > | | > ViewSalesReportItem UpdateSalesReportItem (the actions that handle requests) > > But that isn't very flexible, and may break down in practice. It would be > easy to inherit from the wrong action, perhaps run into situations where you > would want to inherit from multiple base actions (can't do that), override > the wrong method or forget to call a method in the superclass or your > action, or break the security on an action like ViewSalesReportItem because > you made changes to SalesReportItemAction while implementing some > requirement for UpdateSalesReportItem. Perhaps all of that is manageable > after all, but my current thoughts are that action inheritance like this > could be trouble and should thus be avoided for our security checking > purposes. > > > And back to your original proposal... It is fairly common for someone to > email a URL to some page in an app to someone else (by chance or by request > from a user who can't see a page that someone else can). If it is just the > request URL+parameters that are encyrpted into the key, anyone with that URL > can get to the page if you don't have any other security checks. You could > encypt the URL+parameters+username to make the key unique to each user. But > that's a lot of stuff to encypt into a query string parameter. But even then > anyone who figures out how to encode their own params would have free reign > over the system. I think it is best to do active checking to avoid creating > any loop-holes that could be exploited to run wild on the system. With > active checking, you might accidentally create a few holes here and there, > but there is no opportunity for someone to make a "master key" like there > would be with the encryption scheme. If you ever had to change the > encryption key, it would invalidate any bookmarks that your users may have > made to pages in your application, too, which may upset them. > > -Max > > ----- Original Message ----- > From: "Ross Sargant" <[EMAIL PROTECTED]> > To: "Struts Users Mailing List" <[EMAIL PROTECTED]> > Sent: Monday, September 01, 2003 2:59 PM > Subject: Verifying integrity of URLs > > > Hi, > This may be a little off topic, but I thought I'd ask what the experts > thought. > Many actions often take URL parameters. For example a catalog system's > "viewItem" action might include an id number for the > item you wish to view. The action uses this ID to pull something out of your > RDBMS (ideally through a service interface), sets a request attribute and > then forwards to a JSP to show the relevant data. > > Now imagine the case where there are complex rules governing who should be > able to view what items. Say for example that a certain user can only view > one category of items (which would obviously be enforced by the search > interface-you would never generate a link to something they weren't supposed > to see in your search results). > > What is the best way in general to ensure that the user is not playing > around with url parameters (in this example by manipulating the id > parameter) to get at things they shouldn't. Assume for the moment that the > RDBMS cannot help you solve the problem.I don't really see how Roles help > here because my understanding of Roles is that they only enable and restrict > actions. > > One option is to include the security validation in the ViewItem action > itself so it will not just blindly display whatever object the parameters > referred to.This seems like a problem that might occur in numerous different > places though which means it might be benificial to have something more > generic. > > My other thought was to append a URL parameter that is basically a digital > signature of the entire URL+query string (before appending the signature). > Assuming for now that the private key is safe on the server, then this would > provide a generic way to prove that an incoming request came from a link > generated by the site. This approach takes the view that if the user is not > meant to see or do something, they are never presented a link in the first > place to access it and it is impossible for them to fake a get request that > works without knowing the private key. This might introduce peformance > concerns.Note that I'm not even talking about public/private key crypto > here.. just simple single private key encrypt/decrypt. This would really > work for any combination of action+parameters you were concerned about. > > I was wondering if anyone out there had any better ideas or advice on how > they handle this type of problem in an MVC style application while keeping > things fairly simple. > > Ross > > > > > > > > > > > > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [EMAIL PROTECTED] > For additional commands, e-mail: [EMAIL PROTECTED] > > --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]