comments (not for humans)

The 8th item on the OWASP Top 10 is A8 - Failure to Restrict URL Access. This one is kind of interesting as what you see in the browser and what you see on the server are more often than not two very different things in javascript driven web apps. This is especially true for single page webapps.

But first though, here is the risk rating from OWASP:

Threat Agents Attack Vectors Security Weakness Technical Impacts Business Impacts
______ Exploitability
Anyone with network access can send your application a request. Could anonymous users access a private page or regular users a privileged page? Attacker, who is an authorized system user, simply changes the URL to a privileged page. Is access granted? Anonymous users could access private pages that arenít protected. Applications are not always protecting page requests properly. Sometimes, URL protection is managed via configuration, and the system is misconfigured. Sometimes, developers must include the proper code checks, and they forget.

Detecting such flaws is easy. The hardest part is identifying which pages (URLs) exist to attack.
Such flaws may allow some or even all accounts to be attacked. Once successful, the attacker can do anything the victim could do. Privileged accounts are frequently targeted. Consider the business value of the exposed functions and the data they process.

Also consider the impact to your reputation if this vulnerability became public.

Why is it different?

Single page webapps make use of, as the name implies, a single static HTML files, which loads a simple framework and all the different javascript and CSS files used by the application. Because it is static this file never includes private data. The data in the application is typically loaded in the form of JSON from a REST backend.

In order to be able to navigate (use the back button, create bookmarks etc.), the applications will typically use relative URIs starting with a hash (#). So instead of: the URI might look something like: There is no anchor named "/article/13". Instead changes in the hash value are picked up by javascript events, and the page changes accordingly. The server will thus see something like: GET
GET http://examples/api/article/13
where the last GET request returns JSON for the given article.

Newer applications may use pushState(), which means the URI may still look like: However the server will still see the two requests as described above.

So what about "Failure to Restrict URL Access"

The first thing to note, is that restricting URIs on the client side, doesn't really have any security benefits. We should still hide UI elements (buttons/links etc.) that the current user does not have access too. But we cannot rely on it for security, as the user can always alter the client side functionality through firebug etc.

This means that any URI restrictions we want to impose, need to be added on the server side. We need to make sure every JSON service does authorization in order to see if the currently logged in user has access to the service and referred data. For instance we need to check that only admins have access to admin service, while we may want any user to be able to see user profiles, but only allow the user himself to edit his own profile. We need both vertical (role based) and horisontal (data based) access control.

URI canonicalization

With regard to implementing security based on URI access on the server, we need to make sure that we either define the access control programatically within the given REST service, or that the component in charge does URI canonicalization.

URI canonicalization is the process of normalizing the URI, so that different representations of the same URI, have the same result. Consider a URI access control that limits access to /api/admin to users in the admin role. What happens if we access /api/article/../admin. We should still get the same result.


  • We implement URI restrictions on the server side
  • For usability reasons we could/should also do it on the client side, but client-side only is not sufficient
  • If we are to do authorization directly on the URIs, we need to do canonicalization before authorization
comments powered by Disqus