Lock down extensions and session cookies on your own lab
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
- Write
/tmp/browser-policy.jsonin the format Chromium-based browsers read for managed policy: anExtensionInstallBlocklistcontaining*(block everything by default) and anExtensionInstallAllowlistlisting 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. - Write
/tmp/app.py: a minimalhttp.serverhandler bound to127.0.0.1:8099that answersGET /loginwith status 200 and aSet-Cookie: session=<random hex>header -- deliberately with no attributes. Start it in a second shell. - 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. - 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) andMax-Age=900(a fifteen-minute session limits how long a stolen one is worth anything). - 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,HttpOnlydoes 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.