Earlier this week we iterated on our agile project to assure that we have sufficient application security to meet our user’s implicit requrements.
Read on for updates on our implementation of the security constraints, and progress on the next feature to be implemented.
In our previous article defining constraints, we fundamentally established a user goal of trust. Trust that their work would not be misrepresented, and trust that their privacy would not be compromised. We’ve implemented the functionality to address these goals – at least enough for the first public releases.
Ruby on Rails promotes a model-view-controller design approach. What this means is that different parts of the code do different jobs. Views present an interface for the users. Views display information, and allow users to interact. Controllers are responsible for managing the user interaction requests. Controllers send users from one view to another, and reject or satisfy requests from users. Models encapsulate the business rules and functionality of the software. They do all the real work.
You can imagine the flow of an interaction with a Rails application as follows:
- User browses to a URL and views a page (View).
- The application selectively presents data, and selectively exposes ways for users to interact (View).
- User requests an action such as ‘write a review of an article’ or ‘login’ or ‘show me all the articles that I’ve rated’ (View).
- The application rejects or attempts to satisfy the user’s request (Model).
- The application (Model) will provide the service/data/etc to satisfy the user’s request to the controller (Controller).
- The application (Controller) will forward the response from the model to the appropriate view for display (View).
- The application (View) will render the results of the user request for the user (User).
I mention this flow because this architecture encourages a deep security security model.
All interactions with models (by convention) happen either from controllers, or from other models (classes). Controllers, in theory, handle requests from views. Views are the gateway to our application. Consider the requirement that a user can only view her own email address. We could satisfy that requirement just by checking to see if the current user (the person at the keyboard) is the user who’s information is being displayed. This constraint is necessary but not sufficient.
We can’t truly validate that all external interactions with controllers come through views. Software can be written to impersonate an actual user, in order to interact with a website in undesired ways. So if we only implemented view-level security, we would still have a bug.
Controllers can also be protected, so that they always reject unauthorized requests. This way, even requests that don’t come in from one of our views will be protected. This is essentially protection against unanticipated (but reasonable to expect) interactions with the outside world.
We can’t add a constraint that a model only “do the work” if the current_user is authorized. Models don’t know anything about views, so they have to rely on the controllers to only ask for something when it is appropriate. If there is a better way to approach this in Rails, please let me know.
Deep Security Example
We have a requirement that anonymous users can not submit articles.
- In the view, we can determine if the user is logged in, and if so, present a link to the action that creates a new article. If the user anonymous, the link to the action is never rendered.
- In the controller, we can determine if the user is logged in, and if not, prevent the controller from creating a new article.
We’ve made several updates to the application to support this type of security around our constraints.
Next Feature for our Project
After reviewing the feedback again, we have identified the ability to write reviews of articles to be the next feature to implement.