In the latest video of our Security Culture series we talk about testing for authorization. You can also listen in on our podcast.

Authorization

Authorization is the idea that a user can only do what they should be able to based on their role. It is synonymous with access control.

Consider the case of a consulting firm with:

  • Consultants that record time and submit timesheets (Let’s say Joe and Brian are consultants)
  • Managers who approve timesheets (Let’s say Matt is a manager)

There are several types of authorization that need to be implemented in a typical time tracking system.

We need vertical access control implemented to prevent a consultant from approving their own timesheet.

We need horizontal access control or instance based access control to prevent Joe from seeing, modifying or submitting Brian’s timesheet.

Unfortunately, in all my years as a developer, I often observed that we needed to apply security to search functions and admin functions but not necessarily update, delete and view functions on an instance - because we thought it would somehow be very difficult to create a fake request. I believe this issue is common in real world applications. We certainly see it in many pen tests.

Implementing Access Control

Implementing vertical access control often comes down to restricting public routes, and applying checks at any controller (or service) method that is exposed to ensure only users in the correct role are able to call that endpoint.

Horizontal access control can be trickier because we need to check that the logged in user is accessing their own data or data that they are supposed to be associated to. This could be done in a query, or in a central service.

Either of these could use a central authorization service to perform the actual checks.

Testing Authorization Code

In a penetration test, the ways we might test this are illustrated in the following examples.

Vertical

  1. Log in as Matt
  2. Approve a timesheet (capture that request)
  3. Log in as Joe
  4. Replay the request to approve a timesheet but with Joe’s session

Horizontal

  1. Log in as Joe
  2. Access my timesheet (capture that request)
  3. Log in as Brian
  4. Replay the request for Joe’s timesheet but with Brian’s session

It should be fairly obvious that we can write integration tests that do this exact same thing! It turns out that writing tests for this can be a really effective way to identify gaps in authorization.

Simply fire up Selenium, Cypress or any BDD WebDriver and start requesting different data. The example below shows one way this can be done in more detail.

An Example

There is an example from SWTF, a proof of concept we wrote a long time ago!

Here is the feature:

Feature: person is restricted from accessing project they do not own
  In order to trust the system
  as a user
  each person should only be able to access their projects
  
  Scenario: person creates a project
  Given a new project created by a user
  When a different person attempts to access the project
  Then the system should prevent access

Here is the code behind the DSL:

Given(/^a new project created by a user$/) do
  uuid = SecureRandom.uuid
  @user1 = "fb_user_1_#{uuid}@jemurai.com"
  register_as_user(@user1, "password")
  new_project("Insecure Deirect Object Reference #{uuid}", "Forceful Browsing Desc")
  @url = current_url
end

When(/^a different person attempts to access the project$/) do
  logout(@user1)
  uuid = SecureRandom.uuid
  @user2 = "fb_user_2_#{uuid}@jemurai.com"
  register_as_user(@user2, "password")
end

Then(/^the system should prevent access$/) do
  visit @url
  expect(page).not_to have_content "Forceful Browsing Desc"
end

Obviously, some of the methods in this example are common and captured in a base library: register_as_user, new_project and logout. Once we have some of these base parts started, it becomes easy to extend to write more useful and comprehensive tests.

Conclusion

Go write tests for authorization! It is an easy and effective way to ensure that you’re not leaving gaps open.

References

Matt Konda

Matt is a software engineer. He's our CEO and former Chair & OWASP Board Member.

Want to stay up to date with the lastest from Jemurai?

Sign up for our monthly newsletter!