Lock down extensions and session cookies on your own lab

short · 35 min · Objective 2.3

Task

Two browser vectors in this lesson are closed by configuration rather than by vigilance: extensions nobody approved, and session cookies that scripts can read or that ride along on other sites' requests. Write the browser policy that allows only approved extensions, then run a tiny web app on your lab VM, inspect the session cookie it issues, and fix its flags until it passes.

Steps

  1. Write /tmp/browser-policy.json in the format Chromium-based browsers read for managed policy: an ExtensionInstallBlocklist containing * (block everything by default) and an ExtensionInstallAllowlist listing the IDs of the extensions you would actually approve -- a password manager and at most a few others. An extension's ID is the 32-character string on its store page.
  2. Write /tmp/app.py: a minimal http.server handler bound to 127.0.0.1:8099 that answers GET /login with status 200 and a Set-Cookie: session=<random hex> header -- deliberately with no attributes. Start it in a second shell.
  3. Inspect what it issues: curl -s -D - -o /dev/null http://127.0.0.1:8099/login | grep -i set-cookie. Write down which protections are missing.
  4. Fix the cookie and restart the app: add HttpOnly (scripts cannot read it, so an injected script cannot lift it), Secure (sent only over HTTPS -- mandatory in production, documentation of intent here), SameSite=Strict (not attached to requests other sites start) and Max-Age=900 (a fifteen-minute session limits how long a stolen one is worth anything).
  5. Write /tmp/browser.md: for each cookie attribute and for the extension policy, name the vector from the lesson it narrows and one thing it does NOT stop. For example, HttpOnly does nothing about information-stealing software reading the cookie store from disk, which is why short lifetimes, re-authentication for sensitive actions and device-bound sessions matter.

Verify

curl -s -D - -o /dev/null http://127.0.0.1:8099/login | grep -i '^set-cookie'
python3 - <<'PY'
import json, urllib.request
pol = json.load(open('/tmp/browser-policy.json'))
assert '*' in pol.get('ExtensionInstallBlocklist', []), 'the default is not deny-all'
allow = pol.get('ExtensionInstallAllowlist', [])
assert 1 <= len(allow) <= 5, 'allow list empty, or so long it is not a decision'
assert all(len(x) == 32 for x in allow), 'an extension ID is not 32 characters'
hdr = urllib.request.urlopen('http://127.0.0.1:8099/login').headers.get('Set-Cookie', '')
attrs = {p.strip().split('=')[0].lower(): p.strip() for p in hdr.split(';')[1:]}
for need in ('httponly', 'secure', 'samesite', 'max-age'):
    assert need in attrs, 'the session cookie is missing ' + need
assert attrs['samesite'].lower().split('=')[1] in ('strict', 'lax'), 'SameSite=None sends it cross-site'
assert int(attrs['max-age'].split('=')[1]) <= 3600, 'the session lives longer than an hour'
print('extensions deny-by-default,', len(allow), 'approved; cookie attributes:', sorted(attrs))
PY

The first line shows the header your app now sends. The assertions check both halves of the lab: the extension policy really is deny-by-default with a short, deliberate allow list, and the cookie carries all four attributes with a same-site mode that is not None and a lifetime of an hour or less.

Notes

Notice what none of this addresses: a stolen session token still skips the password and the MFA for as long as it lives, because the sign-in already happened. The attributes make theft harder and shorten the prize; binding the session to the device and re-authenticating for sensitive actions are what make a stolen token useless.

This is an independent study companion for CompTIA Security+ SY0-801 and is not produced by or endorsed by CompTIA.