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 EASY |
Prevalence UNCOMMON |
Detectability AVERAGE |
Impact MODERATE |
______ |
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. |
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:
http://example.com/article/13
the URI might look something like:
http://example.com/#/article/13
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 http://example.com/
where the last GET request returns JSON for the given article.
GET http://examples/api/article/13
Newer applications may use pushState()
, which means the URI may still look like:
http://example.com/article/13
However the server will still see the two requests as described above.
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.
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.