We are thought leaders and visionaries bound by a common mission: if it’s worth doing, it’s worth doing right. Positioned at the intersection of innovation and strategy, we deliver perspectives and insight on topics impacting data, design, and business scale.

Technical Pitfall #2: Leaving Security for Later


Anye Freer
Architect - modifly

In the first installation of my Technical Pitfalls series, I discussed the dangers of building a technology solution without a strong architectural foundation.  Now, I’ll expand upon that concept to introduce Technical Pitfall #2: Leaving Security for Later.  

Of all the features one can build into an application suite, the security model is arguably one of the least sexy. Just about every solution has it, it isn’t necessarily unique and it’s not usually one of the top bullet-points on the list of “Things This Application Should Do to Deliver Value.”  Stakeholders don’t (usually) get excited when they see that you’ve implemented a login page and that Joanna can see a different navigation bar than Joellen can based on their roles.  

The vast majority of applications require some knowledge of who is performing actions in the system and have rules about what those users are allowed to do. In the most complex security scenarios, dozens or hundreds of variations exist regarding what actions a user can perform and which entities they are permitted to interact with at all.  

Consider a medical application that contains HIPAA protected information about patients at a hospital.  Access to all the patient data is on a need-to-know basis, so the role a user plays in the hospital dictates both permitted actions and which data they can access at a granular level.  Doctors don’t have access to all patients’ medical history; only those they are treating.  A lab technician may have access to enter test results for a patient, but not see other parts of a patient’s medical history.  A billing clerk may have access to line item level detail for charges for those lab tests, but not be able to see the actual test results, and so on.

Terminology

Permissions, scope, and roles are the building blocks used to accomplish these security checks:   

Permission refers to an action within the system that can be granted.  For example, “get patient list” might be a permission that can be granted for the patient records application.

This permission can be granted to different people with respect to different entities, meaning with a different scope.  The hospital director might have the “get patient list” permission for all patients currently in the hospital, whereas an x-ray technician might only be able to list the patients with x-ray orders.  

Roles refer to common groupings of permissions associated with users that do the same tasks.  In the patient records application, one role might be “billing clerk” and another might be “physician”.  

Users are assigned to roles to inherit the permissions that are associated with their roles, and then the scope of those permissions can be adjusted as necessary.  Roles are a convenient method of granting multiple permissions to a user in a common, predictable fashion.  

Potential Pitfalls

As the complexity of the security requirements increase, so does the criticality that a robust and flexible roles and permissions model be built into the system early. If an unwary team builds the application’s functionality, navigation and features first and then tries to limit who can perform what functions on which records without a robust security model, several things are likely to happen:

  • Some areas of the application will get missed and not have security applied at all because the framework isn’t providing checks and balances.  For applications with protected data, the danger to the business in this scenario is clear.

 

  • Permission checking logic will be convoluted “if this or that but not this other thing unless they also own a cat that lives in a banana, then it’s ok”.  Convoluted logic is harder to maintain and more likely to be flawed.

 

  • Security code will be interspersed with business logic, violating separation of concerns and lowering maintainability.  Any changes to security rules will likely require writing new code and/or manual alteration of data; which reduces adaptability and the ability for non-technical managers to “self-service” the permissions for users they control.

Security Check Points

However,  if your system is designed with proper separation of concerns, then security should be checked at several levels (at minimum):

  • Page Level – should the user be able to access a particular page at all?  A page can be secured either by creating a page-specific permission or by requiring some combination of one or more permissions to access it.  Building this feature into the routing system reminds the developers to think about who is allowed to see the page when they first build it.

 

  • Function / Link Level – should specific functions on a page be visible or hidden/ disabled?  It’s generally poor usability to allow a user to attempt an action and then tell them they weren’t allowed to do it.  If an action can be associated with a permission, then the application can tell if the action should be enabled. Implementing separate functions that are permission-specific as separate widgets will lead to the cleanest separation of application logic and security logic.

 

  • Data Service Level – should the application be permitted to request or alter specific data on behalf of that user?  Most service frameworks have a mechanism for declaring the permission(s) required to access and will automatically check for compliance;  never rely on the user interface to guard the service layer from forbidden requests!

 

  • Entity Level – is the requested data record accessible to the user?  A patient should only ever be able to see their own medical records, not those of other patients.  This level is determined by the scope of the permissions defined at the data service level and is usually managed by row-level record ownership or assignment.  Accessing data via stored procedures that enforce ownership instead of ad-hoc SQL queries is a helpful strategy.

If your business dictates that different users need to be able to perform different functions, the architecture should be planned to address this need up front (or as early as possible) with a consistent and coherent implementation strategy that accommodates both current needs and can adapt to changes to those needs.  

Too many times we read in the news about security breaches that likely resulted from lack of proper security planning; you don’t want the next article to be about your organization.