Client-side web security

We have seen how SQL injection can compromise the security of web application databases on the servers. There are other kind of attacks that work at the client-side.

Sessions

Web applications, as standard applications, usually have a state. For example, when a user logs into a web account a session is started and the web application remembers that the user is authenticated, giving access to her data and resources. This state needs to be represented in the browser in order to implement this session abstraction. This is usually done by storing a freshly generated session token that works as a “session password” keeping the user logged in during the entire session.

The session token can be stored in various ways. For example:

  • As a browser cookie, that is attached to any subsequent request to the server;
  • As a URL parameters in links;
  • As a hidden form field.

Notice however that URL parameters are exposed in logs and referrers. Moreover, hidden form fields are only visible when a form is submitted. In fact, the most common way is to use a session cookie. However, as we will see, combining different tokens can offer more resistance to session integrity attacks, such as Cross Site Request Forgery.

It is clear that if a session token is guessed or leaked someone else can hijack the session, impersonating the legitimate user. Thus, it is important that the token is unguessable and is kept confidential in the browser.

Cookies

A cookies is set using the HTTP header Set-cookie with the following fields:

NAME     = VALUE ;
domain   = ...;
path     = ...;
secure   = (boolean flag); 
expires  = (when expires);
HttpOnly = (boolean flag)

The browser sends all cookies such that:

  • cookie domain is a suffix of the URL domain
  • cookie path is a prefix of URL path
  • protocol is HTTPS if cookie is flagged secure (see below)

For example a cookie with domain .unive.it and path /teaching will be sent on a GET to the URL https://secgroup.dais.unive.it/teaching/security-course, which has domain secgroup.dais.unive.it and path /teaching/security-course.

A cookie can be deleted by setting expiration in the past. Domain and path are set, by default, to the host and path in the URL. The header can occur multiple times to set more cookies.

The following example shows the creation of two cookies with different paths and the successive deletion by setting a date in the past. Notice that each cookie is deleted separately by specifying the path. Since the current path is /search, when path is not specified the current one is applied.

> document.cookie
""
> document.cookie = "username=test; path=/search"
"username=test; path=/search"
> document.cookie = "username=test1; path=/"
"username=test1; path=/"
> document.cookie
"username=test; username=test1"
> document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; "
"username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; "
> document.cookie
"username=test1"
> document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/"
"username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/"
> document.cookie
""

Exercise: check how cookies are set by inspecting network connections in the browser.

Secure cookies

A typical situation that exposes session cookies is when a site has mixed HTTP/HTTPS content. Even if the login is HTTPS, any access to HTTP pages might send the cookie in the clear, exposing it to a network attacker. The secure flag prevents that the flagged cookie is sent over HTTP connections. For sites with mixed content, it is thus important to set two cookies, a secure and a non-secure one that will be used to keep the user in the session over HTTPS and HTTP pages, respectively.

Notice that the secure flag was designed to provide cookie confidentiality but not cookie integrity with respect to network attackers. In fact, in older browsers (e.g. Chrome and Firefox, before 52) secure cookies could be set even over a HTTP connection. As a consequence, a network attacker might had set a secure cookie of his choice by mounting a MITM attack over an HTTP connection. By setting her own session cookie, the attacker could make the user send sensitive data into the attacker’s account. In recent browsers this problem has been fixed and secure cookies can only be set over an HTTPS connection.

HttpOnly cookies

Another typical attack is when a malicious JavaScript is injected into a page possibly leaking cookies, in a so-called Cross Site Scripting (XSS). The HttpOnly flag prevents that JavaScript access the flagged cookie so to prevent the above attack. It is important that session cookies are flagged as HttpOnly.

Session fixation

Suppose that an attacker is able to set a cookie value of her choice into a victim’s browser (for example via a MITM over HTTP). If the user authenticates the attacker’s cookie might be promoted to session cookie. The effect would be that the user uses the attacker’s cookie as session token which, in turn, would allow the attacker to hijack the session. It is often the case that cookies are set before authentication in a so-called pre-session, thus this attack is not so unlikely in practice. The correct approach is to always refresh the session token when user authenticates.

Stateful vs. stateless

The typical approach to have a (Secure and HttpOnly) session cookie in the browser and all the state information on the server might result in an excessive overhead server-side. An alternative solution is to encrypt the session data together with a user ID and a timestamp using a key that is only known by the server. The encrypted blob is stored in a cookie that is decrypted by the server to recover session data and to check user identity. The server still need to remember the time the user logged-in or out so to check the time validity of the encrypted blob.

Same Origin Policy (SOP)

The Same Origin Policy (SOP) (see, e.g., mozilla page on SOP) restricts access among documents or scripts loaded from different domains. Without SOP, in fact, browsing on a malicious site will allow it to access our session cookies and hijack any open session. Thus, SOP provides a simple form of isolation between web applications running in the same browser.

Two pages have the same origin if the protocol, port, and host are the same for both pages. The following table from the mozilla page on SOP gives examples of origin comparisons to the URL http://store.company.com/dir/page.html:

URL Outcome Reason
http://store.company.com/dir2/other.html Success
http://store.company.com/dir/inner/another.html Success
https://store.company.com/secure.html Failure Different protocol
http://store.company.com:81/dir/etc.html Failure Different port
http://news.company.com/dir/other.html Failure Different host

Notice, however, that IE does not include the port in the definition of origin.

The origin can be set to the current domain or to a superdomain (a suffix) of the current domain. For example, if the origin is secgroup.dais.unive.it it can be changed to dais.unive.it or to unive.it. This is useful when web applications belonging to different sub-domains of the same domain need to communicate. In Javascript this is achieved as (try this on the browser console):

> document.domain = "unive.it"

Assignment to a subdomain of the original one is allowed:

> document.domain = "dais.unive.it"

Assignment to a an unrelated domain is forbidden:

> document.domain = "idp.unive.it"
VM91:1 Uncaught DOMException: Failed to set the 'domain' property on 'Document': 'idp.unive.it' is not a suffix of 'unive.it'.
    at :1:17

Moreover, origin cannot be set to top-level domains (TLD):

> document.domain = "it"
VM226:1 Uncaught DOMException: Failed to set the 'domain' property on 'Document': 'it' is a top-level domain.
    at :1:17

SOP regulates network access as follows:

  • Cross-origin writes are typically allowed. In particular following a link, redirection and submitting a form is always allowed since the reached page is different from the originating one (there is no risk of leaking information to the originating page);
  • Cross-origin embedding is typically allowed. Examples are images, CCS and JavaScript;
  • Cross-origin reads are typically not allowed. For example responses to cross-origin AJAX requests will be blocked, as shown below.

Consider the following example:

var xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", "https://www.google.it");
xmlHttp.send( null );
(index):1 Failed to load https://www.google.it/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://secgroup.dais.unive.it' is therefore not allowed access.

We notice that the GET is sent to the target site www.google.it which answers (cross-origin write) but the answer is rejected by the browser as it violates SOP (cross-origin read). We also notice that the error specifies that “No ‘Access-Control-Allow-Origin’ header is present”. This header is part of Cross-Origin Resource Sharing (CORS), a mechanism that can be used to relax SOP and explicitly allow cross-site read access to selected resources.

SOP for cookies

The Same Origin Policy for cookies is a bit different from what we have seen so far.

First of all, we have seen that the origin takes into account protocol, host and port. For cookies the protocol is optional and the path is considered instead of the port. So the origin for a cookie is the triplet [protocol], host, path (where protocol is optional).

SOP for reading cookies

We have seen that the browser sends all cookies such that:

  • cookie domain is a suffix of the URL domain
  • cookie path is a prefix of URL path
  • protocol is HTTPS if cookie is flagged secure (see below)

It is important to notice that the restriction on path is just for performance issues (cookies are not sent if the path is not a prefix) and not for security. In fact, SOP does not prevent pages under different paths of the same domain to access each other DOM.

SOP for writing cookies

Domain che be set to any suffix of URL-hostname except top-level domains. For example, .unive.it will specify a cookie that applies to any subdomain of unive.it. Path can be set to any prefix of the current path.