Alexei Antipov's blog Blog of an opinionated javascript developer

What every web developer should know about same-origin policy

Every web-developer has ever met with the subject called Same Origin Policy (SOP) but even many web-professionals do not know what it exactly is, who is responsible for implementing it and how to use it to build modern secure web applications. Moreover, it is difficult to find good resources on this topic that describe it in simple words. At the same time, it is very important for every web-developer to grasp the concept 'cause it is the cornerstone of web application security model and many web resources rely upon it.

SOP is a big topic and I aren't gonna cope all the aspects and corner cases of it. What I'm actually gonna do is to help you to get your head around it, understand the basics and grasp the ideas behind it.

What SOP is

Unfortunately there is no single and concise definition of the concept, that would cope all the aspects of its application. To start explaining the topic I think it would be helpful to check the ideas behind the concept first.

Ideas behind SOP

User can visit several websites with a single browser simultaneously by opening new tabs or windows. Lets consider an example of logging into internet-bank account and having opened other website in a different tab. I'm sure that as a user you would not want to grant other websites access to your bank account - to read any info from it. So I think you'd like browsers to impose restrictions on what scripts from the document opened at one tab can do with the document, opened in other tab. And browsers actually do this thing and such sort of restrictions is called Same-Origin Policy.

Of course SOP scope is much bigger the case of two opened tab and covers a lot of other things. But the mentioned case helps to understand the main idea behind SOP - restrict reading (stealing) confidential information.

The SOP was originally implemented in Netscape Navigator 2.0 and since then it was incorporated into other browsers.

Nowadays, SOP's scope goes beyond inter-tab (windows) communications and is incorporated into many other schemes of communications.

Who is responsible for imposing restrictions defined by SOP?

As it is became clear from the above it is browsers's responsibility to impose restrictions defined by SOP. It is your browser that restricts scripts from other tabs from reading information at tab with opened internet-bank account page.

The SOP topic is quite broad and there are some differences in implementation of SOP across browsers. But in general most things defined by SOP work in the same way across main browsers.

Origin notion.

As it is clear from its name, SOP is built around a concept of origin.

Lets find out what it is.

Each document or resource in Web is identified by url. URL consists from several parts and in terms of SOP a combination of scheme, host, and port defines an origin of a web resource.

For example, an origin of a resource found at the url http://www.w3.org/Security/wiki/SameOriginPolicy consists of http scheme, www.w3.org host and 80 port (default port). Two resources have the same origin if, and only if, their urls have the same scheme, host and port. Origins of documents http://example.com/doc1.html and https://example.com/doc2.html aren't the same, 'cause they have different schemes http and https.

SOP and Origin.

In general, browsers implement SOP by isolating resources from different origins and permitting controlled communication between them.

There are quite a lot of different types of possible communication and SOP application varies depending on the type of communication.

Communication between 2 different opened documents (web pages).

Access to documents loaded by browser is represented by Document Object Model. Documents can be loaded in separate tabs, windows or iframes. No matter the way documents were loaded they obey a simple principle: document have access to other document's DOM if and only if both documents have the same origin.

Browsers provide the following JavaScript API, that allows documents to directly reference each other: iframe.contentWindow, window.parent, window.open and window.opener. If documents do not have the same origin, browsers provide very limited access to Window and Location objects only.

Instantiation of network requests and interpretation of their responses.

During document loading and its lifetime it can instantiate network requests of different types. For example, requests for stylesheets, scripts, images (static assets), ajax requests and others. In terms of SOP application it is convenient to group these types of requests into 4 categories: new document requests, form submissions, embedded objects requests and scripting requests. Let's consider how browsers impose SOP on each of these types requests.

New documents requests.

Browsers permit web pages to open other web pages of any origin. Opened document may replace original one or it may be opened in a different tab or window or iframe. Opening new documents can be achieved by user clicking hyperlinks or by invoking appropriate DOM methods (e.g. window.open).

So browsers do not impose SOP restrictions on opening new documents. But the do impose SOP restrictions on the access to the contents of opened documents, as we have already know from the above. And this behaviour will become obvious if you remember the main idea behind SOP - restrict access to reading information from other origin resources, not to loading or executing it.

Form submission.

Browsers permit web pages to instantiate cross-origin post requests via form submission. And we can think about it as a case of a new document request, 'cause form submission leads to opening a new document, which contents are not available for reading in cross-origin case.

Embedded objects requests.

HTML has a handful of tags, instantiating their own requests and interpreting the responses of those requests somehow. For example, script tags instantiate network http requests for receiving and executing scripts, img tags instantiate network http requests for receiving and displaying images. The general rule here is that browser doesn't not forbid such cross-origin requests. But the response of this requests may only be interpreted and executed and can't be read. For example, we can't get contents of script file, that was received through script tag request. But the contents of this file are interpreted and executed no matter of the script file origin.

Scripting requests.

Nowadays, two most favorite technologies used for doing network requests from scripts are XMLHttpRequest and WebSocket.

XMLHttpRequest object provides API for doing HTTP requests. This API is quite sophisticated and provides a lot of configuration options for customizing requests - HTTP method, headers, etc. Browsers do impose SOP restrictions on Ajax requests and a while ago they completely forbade doing cross-origin ajax requests, 'cause the response of these requests is always fully available to the script. But currently browsers support doing cross-origin requests using CORS, which allows resource owners to determine which origins their resource will be available for. For example, http://foo.example.com page can instantiate request to the http://bar.example.com page and get and read the response of the request if the owner of the http://bar.example.com site permits to do so.

WebSocket is a different protocol for network communication and browsers do not forbid cross-origin communication using this protocol and defer it to WebSocket server owner to define which origins have access to it.

Summary

Same-origin policy is a cornerstone of web application security model. It instructs browser to restrict communication between resources with different origins and thus preventing malicious web pages from stealing your confidential information.

Most common applications of the policy discussed above should get your head around of the concept and help you to build secure web applications.

References

http://www.w3.org/Security/wiki/SameOriginPolicy
http://www.w3.org/html/wg/drafts/html/master/browsers.html#origin
http://www.w3.org/TR/cors/
http://tools.ietf.org/html/rfc6454
https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
https://developer.mozilla.org/en-US/docs/Web/HTTP/AccesscontrolCORS
https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy
http://blogs.msdn.com/b/ieinternals/archive/2009/08/28/explaining-same-origin-policy-part-1-deny-read.aspx

What is end-to-end testing and how it works.

My previous post was about unit-testing. I described what it is for and how to use it. But unit-tests only test separate units of code in isolation, they don't test how those units work together. So we also need another type of testing, that can help us to ensure the app as a whole works correctly. In this post I'm going to talk about end-to-end (E2E) testing.

What end-to-end testing is for

End-to-end testing is all about checking a work of your app as a whole, not a work of individual units of code.

During E2E testing we consider our app as a black-box only dealing with UI exposed to the user. Such testing is fulfilled from user's point of view to ensure that separate app features work as expected. For example, it may include checking login/logout process, registration process, etc.

For small projects with a single developer it may be sufficient to do manual E2E testing: fill the form => click a button => see results. But when an app is quite large and there are multiple developers it becomes hard to manually check each feature. And there ways to automate end-to-end testing.

How it works

As we can understand now E2E testing is kind of dynamic testing, i.e. it requires code execution. The mechanism of automatic E2E testing is quite simple.

  1. To test a feature developer writes a E2E spec, that defines:
    • what actions needs to be done (load a page, fill a form, click buttons, etc.)
    • assertions about desired result (new page loading at certain url, loading of modal window, showing an warning message, etc.)
  2. Developer runs a program that connects to a browser and uses the spec to do all the defined actions.
  3. The program uses the spec to compare the actual results with the desired results, defined in the spec.
  4. The program notifies a developer about results.

Here is an example of how an E2E spec may look like:

driver.get('http://www.example.com', function() {
 driver.findElement(By.name('username'), function(q) {
   q.sendKeys('Alexey', function() {
     driver.findElement(By.name('submit-button'), function(sbmtBtn) {
       sbmtBtn.click(function() {
         driver.getTitle(function(title) {
           assertEquals("Search results for 'Alexei'", title);
         });
       });
     });
   });
 });
});

driver here is a program, that communicates with a browser.

Which tools are used in automatic E2E testing

  1. To run E2E specs you need selenium-webdriver npm package installed. This program is able run specs against your application in all major browsers - Chrome, Firefox, IE.
  2. To write specs you need a framework, like Jasmine.

AngularJS developers have a bonus - there is a node.js program Protractor, built on top of selenium-webdriver, that greatly simplifies writing specs for angular.js applications.

Links and references

WebDriverJS: https://code.google.com/p/selenium/wiki/WebDriverJs

Jasmine: http://jasmine.github.io/

Protractor: https://github.com/angular/protractor

What is unit testing and how it works.

With the raise of javascript use we can watch how js apps become bigger and bigger. For the last 5-10 years the complexity of javascript apps has increased enormously. Building of such apps is impossible without well-tuned testing process. So every javascript developer should know what testing actually is and how to use it. I gonna tell you about most popular approaches to testing js apps.

What kinds of testing are there?

There are 2 most popular approaches to testing js apps, that complement each other. These are unit-testing and end-to-end testing. What do they actually do, why and when should we use each one? I gonna write about end-to-end testing in my next post. And this post describes unit-testing.

Unit-testing

Why should we use it?

Unit-testing helps us to ensure that each part of our code works as expected under different conditions in different environments.

There are also other benefits unit testing brings us:

  • understanding of what each code unit does and what it is supposed to do.
  • it urges us to write cleaner and more robust code, breaking it into separate loosely coupled components.

How it works?

Unit testing is all about testing individual functions and classes. It utilizes dynamic testing, i.e. it executes the function under test and checks its output, side effects and maybe exceptions handling.

It is important to note that when tested, the function under test is executed in isolation from the rest of the code and all dependencies are mocked.

Consider the following example:

function loginUser(username, pass) {

  return server.login(username, pass)
    .then((result) => {
        notify.success('Congrats! New user has been created');
        return result;
    })
    .catch((error) => {
        notify.error('Some error occurred');
        throw error;
    });
}

This a simple function, that implements user login operation. With unit-tests we can ensure that when calling that function

  • a promise will be returned;
  • server.login will be called with passed in parameters username and pass
  • notify.success will be called if server.login succeeded;
  • notify.error will be called if server.login rejected;

How to implement it

To make and run unit tests javascript-developer needs to do the following:

  1. Choose and setup unit testing framework, that determines how we write test specs.
  2. Write test specs.
  3. Install test-runner, that will execute our test specs against source code in different browsers.

There are a lot of test frameworks and test-runners.

In my angularjs projects I prefer to use Jasmine and Karma.

In my next post I'm going to write about end-to-end testing.

Dependencies handling in angular with ES6 classes

ES6 gives us javascript devs a lot of new things and enhancements. It changes how we write our apps. As a developer of angularjs apps I like to write controllers with the help of ES6 classes.

class MyController {
  constructor(service1, service2) {
    this.someProperty = 'Foo';
    //...
  }

  someMethod() {
  //...
  }
}

Properties defined on this automatically become available on scope using controllerAs syntax. The same applies to the methods, defined in class. Cool!

But to have injected services available from inside the class methods you should define them on this, and so to make them public, because ES6 classes don't have private properties and methods yet. There are some workarounds (WeakMap, Symbol), but I don't like them, because they bring complexity to our code. The best we can do now is to prefix our private properties by _, so we can let other developers know that these properties can't be used in views. So our controller code become:

class MyController {
  constructor(service1, service2) {
    this._service1 = service1;
    this._service2 = service2;

    this.someProperty = 'Foo';
    //...
  }

  someMethod() {
    //...
  }
}

Such a code works fine till you try to minify it. Minified versions of this code won't work because controller injections can't be resolved. In ES5 you can use ng-annotate to handle such minification problems. But as for now it doesn't work good yet with ES6. So we should use explicit dependency annotation. Our controller now become to look like this:

class MyController {
  constructor(service1, service2) {
    this._service1 = service1;
    this._service2 = service2;

    this.someProperty = 'Foo';
    //...
  }

  someMethod() {
    //...
  }
}

MyController.$inject = ['service1', 'service2'];

It works. But we can improve it - we can remove the need to keep $inject array in sync with the parameters in the constructor definition and we can also remove the need to publish each of our dependencies separately. Here is how we can do it:

const deps = ['service1', 'service2'];

class MyController {
  constructor(...args) {
    // Publish each service on 'this' with '_' prefix.
    deps.map((val) => '_' + val).forEach((val, key) => {
      this[val] = args[key])
    };

    this.someProperty = 'Foo';
    //...
  }

  someMethod() {
    //...
  }
}

MyController.$inject = deps;

Now we handle all controller's dependencies in a single place -deps constant, and they all are automatically published on this with _ prefix. Good!

You can also apply such a technique of dependencies handling to other application components.

Useful links: