Mozilla HTTP Observatory

Photo by Daniel Novak on Unsplash

In addition to https://ssl-config.mozilla.org/ when setting up your website, there is another wonderful free tool by Mozilla: https://developer.mozilla.org/en-US/observatory

Unlike the Mozilla configurator it’s not as succinct with helping you configure but it is very good nevertheless.

A nice analysis is https://vaibhav.co.uk/2025/03/08/implementing-secure-headers-using-mozilla-observatory/ by Vaibhav Jain.

So a leg up is to start here with this:

<VirtualHost *:443>
    <IfModule mod_headers.c>
        Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        Header always set X-Frame-Options "SAMEORIGIN"
        Header always set X-Content-Type-Options "nosniff"
        Header always set Referrer-Policy "strict-origin-when-cross-origin"
        Header always set Permissions-Policy "geolocation=(), camera=(), microphone=()"
        Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none';"
    </IfModule>
</VirtualHost>

Like the excellent (and free) Qualys SSL Test site it gives you a grade which is a useful metric.

Here is a python program to allow you to run it on the command line:

#!/usr/bin/env python3
import requests
import time
import argparse

def analyze_site(hostname):
    url = "https://observatory-api.mdn.mozilla.net/api/v2/scan"
    params = {
        "host": hostname,
        "rescan": True
    }
    response = requests.post(url, params=params)
    
    try:
        response.raise_for_status()  # Check if the request was successful
        return response.json()  # Attempt to parse the JSON response
    except requests.exceptions.HTTPError as http_err:
        print(f"HTTP error occurred: {http_err}")
    except requests.exceptions.RequestException as req_err:
        print(f"Request error occurred: {req_err}")
    except ValueError as json_err:
        print(f"JSON decode error occurred: {json_err}")
    return None

def get_scan_results(scan_id):
    url = f"https://observatory-api.mdn.mozilla.net/api/v2/results?id={scan_id}"
    print(f"Fetching results from URL: {url}")  # Debugging information
    response = requests.get(url)
    
    try:
        response.raise_for_status()  # Check if the request was successful
        return response.json()  # Attempt to parse the JSON response
    except requests.exceptions.HTTPError as http_err:
        print(f"HTTP error occurred: {http_err}")
    except requests.exceptions.RequestException as req_err:
        print(f"Request error occurred: {req_err}")
    except ValueError as json_err:
        print(f"JSON decode error occurred: {json_err}")
    return None


parser = argparse.ArgumentParser(description="Analyze a website using Mozilla HTTP Observatory API v2")
parser.add_argument("hostname", help="The hostname of the site to analyze")
args = parser.parse_args()
hostname=args.hostname
analysis = analyze_site(hostname)

if analysis and "grade" in analysis:
    if analysis['error'] == None:
      print("Scan Results:", analysis['grade'])
      print("Scan Results:", analysis['details_url'])
    else:
      print("None")

So here is how you run it:

$  ./observatory.py  www.mozilla.org
Scan Results: B+
Scan Results: https://developer.mozilla.org/en-US/observatory/analyze?host=www.mozilla.org