Overview

Working with Same-Origin Policy Restrictions

No Comments

The Same-Origin Policy (SOP) is a security model that almost everyone gets in touch with when developing websites or web applications. Often, this first experience leads to frustration, misunderstandings, workarounds and hacks. But this does not need to be the case. In this blog post I will outline why the same-origin policy is important, how people typically circumvent it and I will present a tool called proxrox which removes same-origin policy issues that typically occur during development.

The Basics of the Same-Origin Policy

The same-origin policy is a foundational building block of web security. It essentially defines protection domains which are used to restrict actions and access to web resources. One such restriction is that scrips executing on http://example.com are not allowed to access resources on http://subdomain.example.com.

Restrictions are applied based on the document's origin where an origin is defined in RFC 6454 Section 4. To put it simply, an origin is a tuple of scheme, host and port (refer to the spec for edge cases). Only when two origins are equal, the restrictions do not apply. Hence the name same-origin policy.

The same-origin policy is active by default and most browsers provide good error messages when actions cannot be executed because of same-origin policy issues. For instance, the following script defines an illegal cross-origin HTTP request.

// document origin: https://example.com
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://codecentric.de');
xhr.send();
 
// fails with the following message in Google Chrome:
// XMLHttpRequest cannot load http://codecentric.de. No
// 'Access-Control-Allow-Origin' header is present on
// the requested resource. Origin 'https://example.com'
// is therefore not allowed access.

Please note that this description does not take Cross-Origin Resource Sharing (CORS), cookie domain matching and other (softer) variations of the same-origin policy into account. Please refer to the respective specifications to learn more about these security models.

Bad Idea 1: Disabling Web Security

The first encounter with web security for many web developers is probably some cross-origin request that occurs during development. I have seen it many times. Developers start "RESTful" services on their local machine on port 8080, try to access it from another origin (typically with file scheme) and are suddenly baffled by security errors like the one shown before. What does a good developer do in such situations? Right, he turns to Google!

In times of stackoverflow.com you would expect to get quality advice and good recommendations, but one of the top rated stackoverflow questions in this regard is about a hack that should never be used:

Disable same origin policy in Chrome

Is there a way to disable the same origin policy on Google's Chrome browser? This is strictly for development, not production, use.

Yes, you can deactivate the same-origin policy in Chrome (and possibly in other browsers) with the --disable-web-security command line switch. But please read carefully what is being disabled: Disable web security. The name of this command line switch is giving me the creeps. It is not just about the same-origin policy, but complete web security. It falls in line with the -–allow-file-access-from-files switch which is just as bad. I am keenly interested in statistics that show how many developers are using a browser with disabled web security to check their mails or access their GitHub accounts (thereby potentially weakening the security of whole organizations).

Bad Idea 2: Just Activate CORS

Cross-Origin Resource Sharing (CORS) can be used to whitelist origins for specific resources. CORS is a powerful tool that can drill small, supported holes into the same-origin policy. Unfortunately it can just as well be used to drill seemingly small holes that are unstable and, again, dangerous for organizations. CORS becomes dangerous when developers whitelist all origins (via *) and also allow credentials to be sent. This can potentially enable dangerous Cross-Site Request Forgery (CSRF) attacks.

Organizations should give CORS some serious thought, especially before whitelisting all domains. I have seen CORS being activated for development purposes using feature flags. This can be done as long as there is a good configuration management processes in place. This process must ensure that development features are not enabled in production environments.

Proxy Servers

The same-origin policy is implemented and applied by web browsers. As such other applications, e.g. servers, are not restricted by it and may freely access web resources on arbitrary origins. For instance, your server can access any web resource using Apache HttpComponents, Node's http module or any other library that provides an HTTP interface. Of course this also means that the applications' security is our own responsibility!

Proxy servers are an example for server-side components that are not subject to the same-origin policy. Proxy servers are incredibly handy and can be used for a variety of tasks like proxying, server-side includes, caching, SSL termination and many more. Proxying is one feature that is interesting as far as the same-origin policy is concerned. Origins can be combined using proxies and hence the same-origin policy can be circumvented. Let us look at an nginx configuration that is proxying a web API under a new origin.

# configurations that are not of interest for the purpose of
# this blog post were elided.
 
http {
  server {
    listen                   4000;
 
    location / {
      root                   /var/www;
      try_files              $uri $uri/index.html $uri/;
    }
 
    location /api {
      proxy_pass             https://api.example.com;
      proxy_set_header       X-Real-IP $remote_addr;
      proxy_set_header       Host $host;
      proxy_set_header       X-Forwarded-For $proxy_add_x_forwarded_for;
    }
  }
}

Proxy servers are typically used for production and test environment, but not for development environments. This is a sad truth! Sad because proxies are an important part of the infrastructure. Proxies can change caching configurations, limit file upload and header sizes, reject alternative protocol traffic, e.g. websockets, make an application available under HTTPS. Proxies even extend the space of possible solution through server-side includes (SSI) and edge-side includes (ESI) as well as client-side certificates! We should be using proxies as part of our development environment to reap these benefits, get more design choices and to further align production and development environment.

Proxrox: Proxy Servers for Development Environments

This is what proxrox is for! Proxrox (proxies rock) can start local nginx instances, without super user privileges nor complicated configurations to

  • align production and development environments,
  • use the production proxy settings during development,
  • have more design choices like server-side includes,
  • combine multiple origins to circumvent same-origin policy issues without hacks,
  • test the application under SSL and alternative protocols like SPDY,
  • test page-optimization effects under production like settings (SSL and GZip),
  • test behavior when running behind a proxy.

The best of all: It is easy to use! The following configuration can be started via proxrox start .proxrox.yaml (given that the configuration is located in a file named .proxrox.yaml, the recommended file name). Proxrox starts a local nginx instance with the nginx configuration file shown in the previous listing, i.e. files from the /var/www directory are served and the api server can be contacted with the /api path prefix. This means we have a sufficient same-origin policy compliant way to contact the https://api.example.com server!

port: 4000
root: /var/www
proxy:
  /api: https://api.example.com

There is more: The following configuration starts a local nginx instance that is accepting HTTPS connections on port 4000. Proxrox is capable of achieving this by generating self-signed certificates in temporary directories. Additionally, the nginx instance will use the SPDY protocol for browsers that support SPDY for improved web performance. It will also activate server-side includes which can be used to load HTML fragments, e.g. for ROCA compliant systems.

port: 4000
root: /var/www
tls: true
spdy: true
ssi: true
proxy:
  /api: https://api.example.com

Conclusion

The same-origin policy is a core web security model that is implemented in all web browsers and backed by specifications. While very important and useful, it is often an impediment for first time web developers and commonly misunderstood. While certainly possible, the solution is never to deactivate browser security. CORS and proxy servers provide means to circumvent the same-origin policy by whitelisting domains and actions, or by combining origins. An appropriate strategy needs to chosen wisely as inconsiderate usage of either strategy weakens and potentially endangers the security of users and organizations.

Proxrox can be used to avoid same-origin policy issues during development. Additionally, it can help improve the production and development environment parity. Parity between these environments are great in order to avoid and find environment specific issues as well as to optimize for the target infrastructure.

Comment

Your email address will not be published. Required fields are marked *