Designing for security:

When we talk about designing for security in this document, we are essentially talking about application level security at the program level and not talking about Application Server,Operating System or Network Security. This document talks about design principles which when applied while designing an application would ensure that the application can easily incorporate security checks of varying complexity, from basic validation such as invalid logins to OWASP vulnerabilities to finding out hacking attempts through behavioral analysis, the design principles in this document provides a mechanism to incorporate such checks within the application without much hassle.

Today security is a big concern for any organization. Organizations today are spending exorbitant sums of money, paying various consultants to ensure that their applications are secure. The trouble is often when the consultants give their advice, it becomes difficult for the developers to implement their advice since their application is not really designed in a manner that security can be implemented. The application is currently designed in a manner which makes it cumbersome to perform security checks. Below are some of the ways in which application design inhibits security.

Security as an add on:

Today most applications are designed keeping responsiveness or functionality in mind and not keeping security in mind. This often results in unsecure applications which are not flexible enough to accommodate security checks. Applications need to be designed security first ensuring through the design that any security checks which may need to be applied in the future can easily be incorporated into the application.

To achieve this each tier of the application should be properly layered with each layer containing multiple stages with proper linkages and hierarchies between stages as and when necessary.

In a n-tier application each tier typically has a number of layers. For example in a 3 tier application (UI,Middle-ware,DB) the UI, middle-ware and DB would contain multiple layers. A tier contains multiple layers and a tier for purpose of this article refers to the physical unit where the code runs.

A layer is defined as the logical unit within a tier. The logical unit is usually formed by grouping artifacts which handle a particular functionality or cater to a particular role in the tier. For example in web applications the Middle-ware consists of a layer which takes a request from the web and performs all operations which involves working with web constructs like session . We call this layer the Web Layer/Controller. Based on this definition any artifact which performs operations which involves working with web constructs comes under the Web Layer. This is an example on how layers are determined and demarcated within a tier.

Another frequent observation linked to security are teams trying to create a separate layer for security and applying it to a single layer within single or multiple tiers. Applying security only on one layer might work in some cases but is not a definitive approach as an attacker might be able to get past that layer and might hack into the next layer. Thus all layers and their stages needs to be made secure and a holistic approach needs to be taken to keep the entire application secure.

Layers not defined clearly:

A common occurrence which becomes an anti-pattern for application security is the lack of proper definition of layers for a particular application. While dividing the application into layers, each layer must have a proper definition and fixed responsibilities. However if the definition and responsibility of the layers are not fixed then one layer might have code to perform logic which ideally belongs to another layer resulting in intermingling of code . Implementing security rules within this intermingled code base proves to be problematic because different security rules need to be applied for different functionalities and since here functionalities are not demarcated applying these rules becomes problematic.

 A very good example of this is business logic being written in the controller and the controller also handling the HTTP requests. Now if business logic related security checks need to be implemented or request related security checks need to be implemented then the intermingling caused here makes either implementation difficult for the developer since there is no clear demarcation between request related functionality and business logic.


Lack of understanding of responsibilities of a layer:

 Even if layers are defined their responsibilities are often not clearly defined. Thus, you could have a layer for handling web requests and a layer for handling business logic. However, if the demarcation between the layer handling web and business logic is not clearly defined, you could have scenarios of session objects being passed from web to business logic layer.

 Each layer should have a clear responsibility defined and based on the responsibility the security checks which needs to be applied by the layer should be determined. A layer should not attempt to apply all security checks, but only those which pertain to its responsibility.

For example, the web layer should be ensuring protected resources are accessed only if the request has a valid session since session is a web layer entity.However, checking whether a particular operation can be carried out by the current user should not be implemented in the web layer since knowing the role rights of the user is not the responsibility of the web layer.

It is important to understand that each layer by itself will never be fully secure. A layer must only have enough security to ensure that it can execute its responsibility in a secure manner. However note that if the responsibilities of a layer are properly demarcated and each layer is totally secure with respect to its responsibility then the overall application flow which would go through a number of layers would be completely secure.

 Lack of abstraction within a layer:

 In today's agile world business always wants things fast, they want prototypes with minimum requirements. Gone are the days where business would list out all the requirements, thus it now becomes the developers job to understand the level of abstraction and to understand how this abstraction has to be brought into the picture while defining layers.

Consider a scenario where there is a web flow which involves a user filling in multiple forms and based on the data entered moving to the next level. Now only with this requirement its quite easy to assume that for each form there would be a controller getting the form data on submit and invoking a service method to save all the data. This would be a simple way to implement the problem but would later be a hindrance for applying security checks because as the number of forms increase this pattern would result in multiple service methods being invoked by the controller with no linkage between them. Thus if any common security check has to be implemented it has to be implemented individually in all the service methods which would result in code duplicacy and maintenance issues .

To avoid this it is important to discern a commonality between the actions of each service method. Removing this commonality from the method definition would result in an implementation unique to that service which then can be abstracted. Defining a template based on the commonality and abstraction would ensure better control over the way services are being implemented . The template would invariably help in breaking the main operation of a service into finite number of stages all linked together in a particular order. This template would be fixed for a layer abstracting only that part which is specific for a particular implementation. In the case of our example related to forms ,since our application is a web-flow, for each form the template could check that all data required for the form submission to be valid is present in the system and if not then it would not allow the submission. The actual submitting of data might be handled by a separate service which conforms to the template's definition. Thus now any common security check can be added to the template instead of being added to each service since now each service conforms to the template definition.

This design approach ensures that within a layer, based on the definition of the layer, all the required stages are properly defined and demarcated thus ensuring that the design is more security friendly as opposed to those implementations where for each functionality, to which the layer caters to, a separate implementation is created independent of all other implementation in the layer.

Communication between and within layers not clear:

 The following points need to be kept in mind when we talk about communication between layers.

Information transferred between layers:

Passing of information between layers is critical for security. As discussed each layer has a responsibility and the layer is only responsible to secure functionality pertaining to its responsibility. When data is passed to a layer, only that much data should be passed as is required for the layer to fulfill its responsibility. If more data is passed than the layer needs to fulfill its responsibility or the layer is allowed to perform operations on the data which are not needed to fulfill its responsibility it increases the difficulty in implementing security checks.

For example consider an application which routes data from a form into a web layer, the web layer takes data from the form and invokes the business layer, once the business operation is successful the web layer is notified of the success and it adds the data to an existing data map which is maintained at the session level.

Now in this case when the web layer wants to execute the business logic based on the new data entered by the user it can invoke the business layer by passing the map as is along with the new data. Note that the role of the business layer is just to perform the business operation based on the new data entered. However since the web layer has passed the map as is, its possible for a developer to write an implementation which modifies the map in the business layer which is not supposed to be done in that layer. Thus the map now contains data which is not only entered in the web

layer but also in the business logic layer. Due to this violation all checks assuming that the map would only be validated in the web layer would be invalidated.

In such a case the Web Layer should pass the map to the business layer as a read only map so that the business layer can only read from this map as per its need. Note that a similar issue could occur if instead of just passing the map the entire session object is passed. 

Communication between layers in case of success and failure:

Having a defined way of communicating between layers would allow security rules to be defined for the entire layer instead of being defined for a secific implementation in the layer.

Consider a scenario like the above where the web layer invokes the business layer but the business layer in cases of errors at times throws exceptions and at times returns a Boolean or some custom Object. In such a scenario it would be difficult for the web layer to identify exception cases from the business layer based since the return type for exception cases is not fixed.

In such a case the web layer would have to write some specific logic for each implementation to analyze why the exception occurred. If however the business layer always throws an exception in case of any issue, with data sent in the exception object to indicate the cause of the exception the web layer can now have a single algorithm to analyze the exception thrown by the business layer and would thus be able to easily identify whether an exception was caused due to a security breach or not and would then be able to apply rules to either block such requests or perform some other action.

Anemic domain model:

 SOA architecture has given rise to POJOs(Plain Old Java Objects) which are being used as dumb objects with only properties and zero behavior. This causes other layers which create these POJOS to perform validations to check the validity of the POJOS perform various operations in their layer when these operations could have well been executed in the POJOs. These extra operations often results in the layer doing more that what it singed up for which invariably results in issues while enhancing the layer with security rules.

If the entity was not a dumb object but an object with behavior a lot of these validations could have been moved to the entity itself reliving the layer of the responsibility of having to perform those validations.Enabling each entity to validate its state, both from a data and security perspective, would ensure that such validations would always be applied whenever the entity was created irrespective of the layer and would thus serve in unifying the rules used for creating entities and would not require each layer to take the additional responsibility of validating the entity. This would ensure that the layer would have code only pertaining to its responsibility and thus adding security rules would be easier.


 Putting it all together:

Once all the above points are incorporated in an application's design the application can be made as secure as needed. For that its important to incorporate checks within tiers and their respective layers in such a manner so that if one layer is bypassed the subsequent layer has checks to handle such a breach. A layer when invoked should validate the data being sent to it by previous layers ensuring that the data sent is valid and the behavior that the data signifies is expected and does not deviate from expectations.

Consider a scenario where in a social media application the user credentials are compromised. The UI tier sends the data to the service invoking the layer responsible for authentication. In case of a login the UI tier, for this social media application, typically sends the username, password, device used and ip address to the server.

The authentication layer, the layer designated to handle authentication for the social media application, should take the user data, wrap it in an entity which would be responsible for validating its state thus also validating the login data ensuring that the user data contains the username,password,device details and ip address. The entity can validate how valid is the data stored in each of the parameters. Thus if the hacker tries to spoof a request without knowing the type of data for each parameter the entity itself would reject the request thus forming the first line of defense. Note that in this case creation of the entity can be considered the first stage of the authentication layer.

If the hacker logs in through the application bypassing the first line of defense given that the IP address and device details are available existing data for a particular user can be checked on these parameters and the layer can capture any deviating and can block the request. This detecting of abnormalities in behavior based in IP address and device is in this case the second stage of the authentication layer.

Lets however assume that the hacker passes this stage also. Now the authentication layer has been bypassed. Lets now say he starts removing friends from his existing list. The layer responsible for removal of friends can keep a count of how many friends are being removed and using a pre-computed threshold value based previous instances where friends were removed from this account and can raise an alarm if the hacker removes more friends than the threshold value highlighting abnormal behavior.

Thus we can see how every layer and stage can play a part in ensuring that in the event of a breach the damage done is minimal.

 Conclusion:

This approach of each layer and stage ensuring security within itself ensures security for the entire application and ensures that complicated security checks can be incorporated taking a layered approach implementing each check in its respective layer designing the application for security and ensuring that any security patches can be incorporated without much hassle.

To view or add a comment, sign in

More articles by Prashant Dutta

Others also viewed

Explore content categories