towerops/test/towerops_web/plugs/security_headers_test.exs
Graham McIntie 9ecd01dc8f Security hardening: remaining audit fixes
- Encrypt session cookies (add encryption_salt to endpoint)
- X-Frame-Options: SAMEORIGIN → DENY (match CSP frame-ancestors 'none')
- Remove unsafe-eval from CSP script-src
- Apply security headers in all environments (not just prod)
- Add GraphQL query complexity limit (max 500) via Absinthe.Plug
- GraphQL introspection already blocked in prod via plug

Closes audit items #6, #7, #12, #13, #14, #16
2026-02-15 12:54:38 -06:00

27 lines
1.1 KiB
Elixir

defmodule ToweropsWeb.Plugs.SecurityHeadersTest do
use ToweropsWeb.ConnCase, async: true
alias ToweropsWeb.Plugs.SecurityHeaders
describe "call/2" do
test "adds security headers to all responses" do
conn = SecurityHeaders.call(build_conn(), [])
assert ["default-src 'self'" <> _] = get_resp_header(conn, "content-security-policy")
assert ["DENY"] = get_resp_header(conn, "x-frame-options")
assert ["nosniff"] = get_resp_header(conn, "x-content-type-options")
assert ["strict-origin-when-cross-origin"] = get_resp_header(conn, "referrer-policy")
assert ["browsing-topics=()"] = get_resp_header(conn, "permissions-policy")
[csp] = get_resp_header(conn, "content-security-policy")
assert csp =~ "default-src 'self'"
assert csp =~ "script-src 'self' 'unsafe-inline'"
refute csp =~ "unsafe-eval"
assert csp =~ "style-src 'self' 'unsafe-inline' 'unsafe-hashes'"
assert csp =~ "img-src 'self' data: https:"
assert csp =~ "font-src 'self' data:"
assert csp =~ "connect-src 'self' ws: wss:"
assert csp =~ "frame-ancestors 'none'"
end
end
end