HTTPS and headers
HTTPS and HSTS
Section titled “HTTPS and HSTS”Serve the application only over HTTPS. CodeIgniter’s forcehttps filter
redirects plain requests, but sends Strict-Transport-Security only on
that redirect, which browsers ignore over HTTP. Set HSTS at the web server
or the TLS terminating proxy:
# nginx, in the server block for 443add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;# Apache, mod_headers, in the VirtualHost for 443Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"Only add includeSubDomains if every subdomain is served over HTTPS.
Headers set by Anvil and CodeIgniter
Section titled “Headers set by Anvil and CodeIgniter”| Header | Set by |
|---|---|
X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy: same-origin |
Anvil on panel pages, endpoint answers and API answers (Anvil\Security\SecurityHeaders, headers already set are kept) |
Cache-Control: no-store |
Anvil on panel pages, endpoint and API answers, file and export downloads |
Content-Security-Policy: sandbox |
Anvil on file and export downloads |
X-Frame-Options: SAMEORIGIN, X-Content-Type-Options, X-Download-Options, X-Permitted-Cross-Domain-Policies, Referrer-Policy |
CodeIgniter’s secureheaders filter (global after) on every answer |
Content-Security-Policy |
CodeIgniter with app.CSPEnabled = true |
Strict-Transport-Security |
the web server or proxy |
The secureheaders filter runs after Anvil and overwrites its
X-Frame-Options: DENY with SAMEORIGIN. Framing is still refused:
frame-ancestors 'none' in the CSP takes precedence over
X-Frame-Options in current browsers. Keep the CSP enabled for this reason.
Content Security Policy
Section titled “Content Security Policy”Anvil works with a strict policy, without unsafe-inline and
unsafe-eval (see Styling). The
AppStarter’s app/Config/ContentSecurityPolicy.php:
public bool $reportOnly = false;public bool $upgradeInsecureRequests = false;
public $defaultSrc = 'self';public $scriptSrc = 'self';public array|string $scriptSrcElem = 'self';public array|string $scriptSrcAttr = 'none';public $styleSrc = 'self';public array|string $styleSrcElem = 'self';public array|string $styleSrcAttr = 'self';public $imageSrc = ['self', 'data:'];public $baseURI = 'self';public $childSrc = 'self';public $connectSrc = 'self';public $fontSrc = 'self';public $formAction = 'self';public $frameAncestors = 'none';public $objectSrc = 'none';public bool $autoNonce = true;autoNonce adds the nonces for Anvil’s <style> element and scripts.
Pages of the application with inline scripts or style="…" attributes
break under this policy; fix them instead of loosening it. To roll out a
change safely, set $reportOnly = true with a $reportURI first.
The global csrf filter protects every form and htmx request
(Config\Security::$csrfProtection = 'session', $regenerate = false).
Exclude only what authenticates differently:
'csrf' => ['except' => ['api/*']], // API: tokens, no cookiesWith a SAML provider, also exclude sso/*/callback. See
Installation.
Reverse proxies
Section titled “Reverse proxies”Behind a load balancer or TLS terminating proxy, CodeIgniter sees the
proxy’s address and plain HTTP unless the proxy is trusted. Then all users
share one IP in the rate limits, the audit log records the proxy, and the
API refuses every request with 403 (https required). Trust exactly your
proxies:
public array $proxyIPs = [ '10.0.1.10' => 'X-Forwarded-For', '192.168.5.0/24' => 'X-Forwarded-For',];CodeIgniter then takes the client IP from that header and the protocol
from X-Forwarded-Proto, only for requests from these addresses. Make sure
the proxy overwrites (not appends to) these headers from clients.