# Mozilla's Observatory

###### October 21, 2016 — Bryan Allred

[Mozilla](https://mozilla.org/) has recently publicly opened up a new tool [Observatory](https://observatory.mozilla.org/) at [observatory.mozilla.org](https://observatory.mozilla.org/).  The tool aims to help developers and security professionals be aware of potential issues and help resolve them for a more _safe and secure_ Internet. This will be a dive in to targetting our own website at [revolvingcow.com](/content/site-root.html) and then listing the issues and how we resolved or justified them. The actual results can be viewed [here](https://observatory.mozilla.org/analyze.html?host=www.revolvingcow.com).

First, we should probably declare where we will be making the modifications. Our server is running on [Caddy](https://caddyserver.com/) which hosts content directly but also acts as a proxy to other internally hosted services (i.e. [Hugo](https://gohugo.io/), [Gogs](https://gogs.io/), etc.). For this example we wanted to focus on our main site which is ran using [Hugo](https://gohugo.io/) on an internal port which [Caddy](https://caddyserver.com/) then proxies all requests to. The nice thing about this setup is:

1. [Hugo](https://gohugo.io/) can be automatically updated via source control  
2. [Caddy](https://caddyserver.com/) can host multiple services and subdomains  
3. [Caddy](https://caddyserver.com/) can handle the SSL and TLS configurations automatically leveraging [Let’s Encrypt](https://letsencrypt.org/) and the ACME protocol  
4. We can explicitly allow paths to bypass the proxy to serve specific static resources

Below is a clean version of the configuration:

```
revolvingcow.com www.revolvingcow.com {
    gzip
    proxy / localhost:5097 {
        except /.well-known
    }
    root /var/www/revolvingcow.com
}
```

To summarize we went from an **F** to an **A+** with an hour investment of time.

## Content Security Policy

- **Explanation**: Content Security Policy (CSP) header not implemented
- **Link**: [https://wiki.mozilla.org/Security/Guidelines/Web_Security#Content_Security_Policy](https://wiki.mozilla.org/Security/Guidelines/Web_Security#Content_Security_Policy)
- **Link**: [https://content-security-policy.com/](https://content-security-policy.com/)

```
    header / {
        Content-Security-Policy "default-src 'none';
                                 font-src fonts.googleapis.com fonts.gstatic.com cdnjs.cloudflare.com;
                                 img-src 'self' *.stripe.com;
                                 object-src 'none';
                                 script-src 'self' cdnjs.cloudflare.com checkout.stripe.com;
                                 style-src 'self' 'unsafe-inline' cdnjs.cloudflare.com fonts.googleapis.com;
                                 connect-src 'self' *.stripe.com;
                                 frame-src 'self' *.stripe.com"
    }
```

| Directive | Value | Description |
| --- | --- | --- |
| default-src | ‘none’ | If we missed a directive or a new one is added we want to fail hard first. |
| font-src | fonts.googleapis.com<br>fonts.gstatic.com<br>cdnjs.cloudflare.com | Our fonts come from Google (which has two addresses) and a CDN. |
| img-src | ‘self’<br>\*.stripe.com | Images should come from our local site or Stripe.io. |
| object-src | ‘none’ | We hate embedding objects :) |
| script-src | ‘self’<br>cdnjs.cloudflare.com<br>checkout.stripe.com | All our scripts should be local, from a CDN, or from Stripe.io for payments. |
| style-src | ‘self’<br>‘unsafe-inline’<br>cdnjs.cloudflare.com<br>fonts.googleapis.com | Most of our styles will come from local, CDN or Google. However, some inline styles are applied and for a quick turn around we went ahead and approved this. In the future we will be moving all inline styles in to our stylesheet since it is the proper thing to do. |
| connect-src | ‘self’<br> \*.stripe.com | All XMLHttpRequest, WebSocket, or EventSource requests should be from ourselves or Stripe.io. |
| frame-src | ‘self’<br> \*.stripe.com | Initially we thought we didn’t load any frames, but it appears Stripe.io’s Checkout API does. |

This does still present errors within the console similar to

> Refused to execute inline script because it violates the following Content Security Policy directive:
> “script-src ‘self’ cdnjs.cloudflare.com checkout.stripe.com”.
> Either the ‘unsafe-inline’ keyword, a hash (‘sha256-yUVnIIasrC7yNIGYh0wvG7kUNfyCWyaJTAY45Bdqztk=’),
> or a nonce (‘nonce-…’) is required to enable inline execution.

This was due to the Google Analytics script being in the header of our HTML. Moving this in to its own file resolved the issue.

## HTTP Strict Transport Security

- **Explanation**: HTTP Strict Transport Security (HSTS) header not implemented
- **Link**: [https://wiki.mozilla.org/Security/Guidelines/Web_Security#HTTP_Strict_Transport_Security](https://wiki.mozilla.org/Security/Guidelines/Web_Security#HTTP_Strict_Transport_Security)

```
    header / {
        # Only connect to this site and subdomains via HTTPS for the next year and also include in the preload list
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
    }
```

Due to there being subdomains we wanted them included as well, but pretty much this is verbatim to the recommendation.

## Subresource Integrity

- **Explanation**: Subresource Integrity (SRI) not implemented, but all external scripts are loaded over https
- **Link**: [https://wiki.mozilla.org/Security/Guidelines/Web_Security#Subresource_Integrity](https://wiki.mozilla.org/Security/Guidelines/Web_Security#Subresource_Integrity)

```
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js" integrity="sha384-CgeP3wqr9h5YanePjYLENwCTSSEz42NJkbFpAFgHWQz7u3Zk8D00752ScNpXqGjS" crossorigin="anonymous"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.96.1/js/materialize.min.js" integrity="sha384-jTuHJ2QIy2SvtA4DSlQe6o/OA1yrU7l8JHdmP1PSSeVohsNTdO7fYmcZVie/Ev/l" crossorigin="anonymous"></script>
```

So this was a fun one and one that was actually on our TODO list. For external script references it is possible to include an additional sanity check on the contents to ensure it has not been tampered with. This is accomplished by the browser by comparing the checksum of the external resource to one predefined within the source. We used [https://www.srihash.org/](https://www.srihash.org/) to generate our hashes for the added benefit of also determining if the external resource is CORS compliant.

## X-Content-Type-Options

- **Explanation**: X-Content-Type-Options header not implemented
- **Link**: [https://wiki.mozilla.org/Security/Guidelines/Web_Security#X-Content-Type-Options](https://wiki.mozilla.org/Security/Guidelines/Web_Security#X-Content-Type-Options)

```
    header / {
        # Prevent browsers from incorrectly detecting non-scripts as scripts
        X-Content-Type-Options "nosniff"
    }
```

Nothing crazy here and just implemented the suggested header.

## X-Frame-Options

- **Explanation**: X-Frame-Options (XFO) header not implemented
- **Link**: [https://wiki.mozilla.org/Security/Guidelines/Web_Security#X-Frame-Options](https://wiki.mozilla.org/Security/Guidelines/Web_Security#X-Frame-Options)

```
    header / {
        Content-Security-Policy "...; frame-ancestors 'none'"

# Block site from being framed
        X-Frame-Options "DENY"
    }
```

We went ahead and covered both areas (`Content-Site-Policy` and `X-Frame-Options`) just to be safe. Right now there are no uses of IFRAMEs within the site, but if there were we could make the appropriate adjustments which are described in more detail in the [associated link](https://wiki.mozilla.org/Security/Guidelines/Web_Security#X-Frame-Options).

## X-XSS-Protection header not implemented

- **Explanation**: X-XSS-Protection header not implemented
- **Link**: [https://wiki.mozilla.org/Security/Guidelines/Web_Security#X-XSS-Protection](https://wiki.mozilla.org/Security/Guidelines/Web_Security#X-XSS-Protection)

```
    header / {
        # Block pages from loading when they detect reflected XSS attacks
        X-XSS-Protection "1; mode=block"
    }
```

Again just implemented the suggested fix and tested to make sure nothing was broken.
