Authorization Checks in REST APIs

Lets take a look at sample REST APIs that allows Students to view their grades and professors to add/update grades.

If a student wants to view his/her grade in English, your system perhaps has a REST API like:

GET /student/{student_id}/english/grade

The Professor perhaps has access to the following REST APIs to be able to view and update any one of their students’ grades:

  1. View a student’s grade

GET /student/{student_id}/english/grade

2. Post a student’s grade

POST /student/{student_id}/english/grade

3. Update a student’s grade

PUT /student/{student_id}/english/grade

Of course there is a portal that the Student logs in to to view their grades and the professor logs in to post and update grades.

A savvy student is able to turn on HttpWatch to view the REST APIs being called by the portal. Lets say, the student A observes that when she clicks on a link to view her English grade, a REST API call is generated that looks like the following:

GET /student/1234/english/grade

What if the student is smart enough to replay this request with a different student id, 6789?

GET /student/6789/english/grade

If there are no proper Authorization checks in the APIs, the student A with id, “1234” is now able to view student B with id “6789” grade.

Even worse if if the student was able to update their own grade. How about the student try the following API?

PUT /student/1234/english/grade with payload “A”

or update someone else’s grade to “F”

PUT /student/6789/english/grade with payload “F”

However, a professor should be able to view, post or update anyone of their students’ grades. All of the above APIs are fair if they are issued on behalf of a professor.

So, every REST API call needs to enforce proper authorization to make sure that the user on whose behalf the API call is being made has access to the Resource on which they are taking action.

Since Java 6, the following Authorization annotations were added to make it easy to decorate methods with Authorization checks:

Annotation Types Summary
DeclareRoles Used by application to declare roles.
DenyAll Specifies that no security roles are allowed to invoke the specified method(s) – i.e that the methods are to be excluded from execution in the J2EE container.
PermitAll Specifies that all security roles are allowed to invoke the specified method(s) i.e that the specified method(s) are “unchecked”.
RolesAllowed Specifies the list of roles permitted to access method(s) in an application.
RunAs Defines the identity of the application during execution in a J2EE container.

However, these are annotations do not allow you to check if the user has access to a specific Resource ID. This is where, I find using Spring Security to be very helpful.

Spring Security provides a mechanism to do Data Level Authorizations using “hasPermission” annotation. Below is a reference from the documentation:

hasPermission(Object targetId, String targetType, Object permission) Returns true if the user has access to the provided target for the given permission. For example, hasPermission(1, ‘com.example.domain.Message’, ‘read’)

This makes it a bit easy to centralize logic for authorization checks. In the case of a REST Call such as POST /student/1234/english/grade “A” would translate in to a hasPermissions check:

hasPermission(“1234”, Grade, “update”) The method has access to the Principal on whose behalf the call is being. So, you have access to the Principal and the Target, and you can verify if the Principal has access to act up on the target ID. In the case of a student, this check returns a true only if the Principal and the Target ID are the same and also the permission is “view”. In the case of a professor, the check may be something like does the Target ID belong to a student that is currently enrolled in the Professor’s class.

If you are using Spring Security or some other framework, make sure you provide an easy way to apply authorization checks to ensure that the Principal is able to act on a given Resource.


Authorizing Access to Data Embedded in REST APIs

Is your REST API vulnerable to Direct Object Reference Attacks?

Designing Client applications using HTML/JavaScript/CSS that call REST APIs to retrieve data is an architecture pattern that lot of companies are adopting these days. In the blog post, I will address a common security vulnerability that the developers expose their applications while implementing the REST APIs.

Lets say you have are building a REST API for your Banking and implement the following REST APIs:

  1. API to retrieve account balances –{account_id}/balance
  2. API to transfer money –{from_account_id}/to/{to_account_id}/amount/{amount}

Although it seems simple enough, the Developers do not verify that the authenticated user (the user logged on) has authorization to operate on the accounts being specified in the API calls. There could be different reasons for this missing security control:

  • Under the covers the API is using legacy code to implement the functionality and the security checks were done in legacy UI that was calling the legacy mid-tier. So, when the Developer is implementing REST API, they are not accounting for the authorization check and are relying upon the UI to enforce the check.
  • The Developers might be under the impression that the user can not change the data in the URL as there is no input from that allows them to control the data as it is displayed as an HTML link on the page. This line of thinking applies to other inputs that could be submitted on the payload such as Cookies, Headers, Query Params, Hidden Inputs, Path Params etc.

In Security, this is called Direct Object References and directly conflicts with REST Design principles to have Unique Ids for Resources. Hence, it is a must that REST API Developers must implement authorization checks on any Ids that appear on the APIs to ensure that the authenticated user (Logged on user) has authorization to access data embedded in the REST APIS.

How to mitigate this vulnerability?

The solution is custom for the API that you are implementing as this is data specific to your use case. The authorization checks could be done at the entry point to your APIs or with in each API to verify that the authenticated user does have access to each data element embedded in the API. For e.g. in the above API calls, verify that the logged on user has access to the Account Id specified in the API call.

Frameworks such as Spring Security, makes this very easy by applying authorization annotations on your REST end points.

The code implementing “Get Balances” REST API could have authorization annotations such as:

@PreAuthorize("hasPermission(#account_id, 'view_account')")
  public Double getBalance(@PathParam("account_id:) Double account_id);

TBD: Reference application that shows implementation details is soon to follow. Please say tuned.

Please suggest frameworks for other languages that you are familiar with.


Implement test cases to verify that the controls is working as expected and is preventing unautjhorized access to resources specified in the API/URI.

TBD: Reference application that shows implementation details is soon to follow. Please say tuned.

Additional Resources