March Docs

BastionCSP

BastionCSP: Content Security Policy nonce injection for Bastion web apps.

Generates a cryptographically random nonce per request, assigns it to the Conn under the key "csp_nonce", and emits the appropriate Content-Security-Policy header.

Typical usage in an endpoint pipeline:

conn
|> BastionCSP.protect()

In templates, retrieve the nonce via:

let n = BastionCSP.nonce(conn)
"<script nonce=\"" ++ n ++ "\">...</script>"

Default policy (strict): default-src 'self' script-src 'self' 'nonce-NONCE' style-src 'self' 'nonce-NONCE' img-src 'self' data: https: font-src 'self' connect-src 'self' wss: worker-src 'self' blob: frame-ancestors 'self' base-uri 'self' form-action 'self'

Functions

fnassign_nonceassign_nonce(conn)#

Generate a fresh nonce (16 random bytes, base64-encoded) and assign it to the Conn under the key "csp_nonce". Returns the updated Conn.

  conn: BastionCSP.assign_nonce(conn)
fndisabledisable(conn)#

No-op: returns the Conn unchanged. Useful to explicitly mark that CSP is intentionally disabled for a route (e.g. during local development).

  conn |> BastionCSP.disable()
fnget_nonceget_nonce(conn)#

Retrieve the CSP nonce from the Conn assigns.

Returns Some(nonce_string) if assign_nonce has been called, None otherwise.

  match BastionCSP.get_nonce(conn) do
  Some(n) -> n
  None    -> ""
  end
fnnoncenonce(conn)#

Return the nonce string, or an empty string if none has been assigned.

  let n = BastionCSP.nonce(conn)
fnprotectprotect(conn)#

Assign a fresh nonce and set the Content-Security-Policy header in one step. This is the primary entry point for most pipelines.

  conn |> BastionCSP.protect()
fnprotect_with_overridesprotect_with_overrides(conn, overrides)#

Assign a fresh nonce and set a customised Content-Security-Policy header. overrides is a List((String, String)) of directive pairs that replace the corresponding defaults.

  conn
  |> BastionCSP.protect_with_overrides(
       Cons(("img-src", "'self'"), Nil))
fnreport_onlyreport_only(conn, report_uri)#

Assign a fresh nonce and set a Content-Security-Policy-Report-Only header, appending report-uri <report_uri> to the default policy.

  conn |> BastionCSP.report_only(conn, "https://csp.example.com/report")
fnset_headerset_header(conn)#

Set the Content-Security-Policy response header using the nonce already assigned to the Conn. Call assign_nonce/1 first (or use protect/1).

  conn
  |> BastionCSP.assign_nonce()
  |> BastionCSP.set_header()