(Sub)origins - An introduction to Suborigins

Same-origin policy [RFC6454] (SOP) is one the most important security feature we have on the web. For instance, without SOP it could be possible for any website to set and read all your cookies. You could say that SOP is a fence around a website.

An origin is scheme, hostname, and port number. For example, http://example.com:80, where http:// is the scheme, example.com is the hostname and the :80 is the port. If any one of these change, you have a new origin.

It's a quite common security defense strategy to use more than one origin to spread out the attack surface (e.g login. and exit.). You can do this by using different ports or a subdomain. However, it could be demanding to create subdomains because they need HTTPS, web server configuration and correct DNS-records.

Historically, an XSS on /foo/ will often mean that /bar/ also is affected by this XSS. This is because they both run in the same origin and therefore share same-origin policy.

The header Suborigin is here to change everything. With this header you will easily be able to "convert" any subpath to a separate origin! This is revolutionary in a few ways.

Note: The standardization of Suborigins is not complete. However, the functionality described in this article will work the same as in the finalization. The "$" character will be used as serialization in this article.

A web without Suborigins

If an attacker have found an XSS on the path /foo, the attacker can easily inject Javascript into an iframe with src of a relative URL (e.g /baz) to be able to execute script on any subpath within that origin. By disallowing iframes with CSP you are still not completely protected.

There's no real mitigation against attacks that are within an origin. CSP can actually help quite a lot by using child-src, connect-src, object-src, form-action and even base-uri. Once an attacker can inject Javascript on the origin, the attacker will have complete access to that origin.

What is a "Suborigin"?

[Suborigins] Provides a mechanism for a server to specify a new origin for a page to run in that is named and contained within the same physical (scheme/host/port) origin. For example, an application running at https://google.com/foo which the server places in the Suborigin namespace Foo will run in a new origin based on the tuple (https, google.com, 443, Foo). This would be considered a different origin space from (https, google.com, 443) or (https, google.com, 443, Bar)

Source: https://www.chromestatus.com/features#suborigins

Suborigins have been in work for quite some time. It have been in Chrome a few times and it started as a CSP directive but is now a separate header. Due to problem with serialization the functionality was removed from Chrome and will be implemented again when the issue is solved.

Example: on http://example.com/hello/ - a Suborigin - header was sent:

GET /hello/  
Suborigin: hello  

In such a case the suborigin will be http://$hello$example.com. A suborigin is not an origin or domain, and therefore not a valid website that you can visit in your browser. Only a different SOP (Same-origin policy) will be applied on http://example.com/hello/. The full origin will be something like
(http, hello, example.com, 80)

Because http://$hello$example.com (a suborigin) does not have the same SOP as http://example.com/, (an origin) a good mitigation against privilege escalation attacks will be in use.

Example: An attacker manages to exploit a persistence XSS on /foo/ and then creates a payload that reads the user cookie and send them to evil.com. On the subpath /foo/, a Suborigin: foo - header is sent, and because of this, document.cookie won't return any cookie, so the hacker won't receive any cookies. This is because the /foo/ subpath have a fresh cookie jar due to it being another (sub)origin.

Note: the cookie attribute path can be bypassed with an XSS. Paths in cookies are not a security implementation and will therefore not give the same protection as suborigins will.

Suborigins are isolated within the main origin. The origin has full access to a suborigin, but not vice versa. Suborigins cannot access other suborigins. So if you want to protect a subpath, all you need to do is send the Suborigin - response header on that subpath.

A simple SOP relationship chart showing how suborigins and origins can access each others. Red arrows means that SOP will deny access.

So to conclude how suborigins works is simply by giving subpaths (e.g /foo/) a new SOP. Attacks will still be possible against that suborigin but the permissions will be limited to the suborigin.

Hacking (with) Suborigins

But what if an XSS is found on a suborigin? What is possible and what can an attacker do? An attacker will still have the possibility to execute Javascript and insert HTML and do other forms of attacks such as open redirects, CSRF, token stealing etc. The attacker will not have the possibility to reach resources that are protected by SOP; that is cookies, different type of storage and not be able to use technologies that uses SOP as a form of separator.

As a defense, you can generate different Suborigin response headers on every site visit. This will mean that every client will use a different suborigin:

$ for i in {1..3}; do curl -LIs example.com/foo/ | grep suborigin; done

suborigin: 500755253730892  
suborigin: 444200995566797  
suborigin: 768839857010527

This will give a good protection if you're afraid of attack against a suborigin. The suborigin namespace should not be predictable of course, which is easier said than done.

Another hack would just to let static resources be in a suborigin. This is a great mitigation against privilege escalation attacks. For example, if a user can upload pictures to /images but manages to upload a HTML-file that executes Javascript - this file would be in a separate origin from /. Because of this, attacks against the main application at / is much harder to accomplish.

My thoughts on Suborigins

Suborigins are a great way of isolate your web application SOP-wise. It's very easy to implement and will give a direct web browser protection. We have Content-Security-Policy that have the possibility to stop XSS-attacks but Suborigins are another interesting way of protection, and I think Suborigins have a great potential on the web.

Same-origin policy is something that makes everything work on the web and to see this functionality be used more can only mean for the better good.

It will be interesting to see how Suborigins will develop and be used the couple of years ahead. Personally I think it won't be used that much because it does not stop attacks, just privilege escalation which often is post-mortem (where the bounty is safe).

You can track Suborigins in Chrome here (very soon!). Firefox will most definitely implement. I hope. The editors draft can be read here.

I hope you liked this article and you can follow me on Twitter for some web sec related stuff not to often: @dotchloe