Skip to content

feat: add Fetch Metadata CSRF protection#10221

Open
memleakd wants to merge 2 commits into
codeigniter4:4.8from
memleakd:feat/fetch-metadata-csrf
Open

feat: add Fetch Metadata CSRF protection#10221
memleakd wants to merge 2 commits into
codeigniter4:4.8from
memleakd:feat/fetch-metadata-csrf

Conversation

@memleakd
Copy link
Copy Markdown
Contributor

Description

This PR proposes adding Fetch Metadata-based CSRF protection to CodeIgniter.

CSRF tokens work, and this PR keeps them as the compatibility fallback. But the web platform and modern frameworks are clearly moving toward browser-provided request context as the better default for browser CSRF protection. Other frameworks have already moved in this direction, or have active work around the same idea, and OWASP documents Fetch Metadata as a defense-in-depth layer for CSRF protection.

The reason is pretty simple: token-based CSRF protection has always been awkward and a source of headaches for many developers. Forms need hidden fields, JavaScript requests need special headers, JSON requests need special handling, cached pages and long-lived tabs can produce stale-token failures, token regeneration can surprise users, and teams regularly end up debugging "why did this normal request fail?" instead of working on the application.

Fetch Metadata gives the framework a cleaner browser-native signal. Modern browsers send the Sec-Fetch-Site header, which tells the server whether an unsafe request came from the same origin, the same site, or another site. That lets CodeIgniter ask a simpler question before touching token verification:

Is this unsafe browser request clearly coming from this application?

If yes, same-origin browser requests can pass without token plumbing. If it is clearly cross-site, it can be rejected before token verification. If the browser does not provide enough information, CodeIgniter falls back to the existing token check.

This keeps the change conservative while still moving new applications in the right direction:

  • New applications use Fetch Metadata first, with token fallback.
  • Upgraded applications without the new config value continue using token-only verification.
  • Missing, none, or unknown Sec-Fetch-Site values fall back to token verification.
  • same-site is rejected by default, because sibling subdomains are not always equally trusted.
  • Apps can opt back into token-only behavior with $csrfUseFetchMetadata = false.
public bool $csrfUseFetchMetadata = true;
public bool $csrfAllowSameSite = false;

With Fetch Metadata enabled:

  • Sec-Fetch-Site: same-origin passes without a token.
  • Sec-Fetch-Site: cross-site is rejected.
  • Sec-Fetch-Site: same-site is rejected unless explicitly allowed.
  • Missing, none, or unknown values fall back to token verification.

So this PR does not remove CSRF tokens. They remain supported and useful as the migration fallback, especially for upgraded applications. But the direction is intentional: new CodeIgniter applications should get a more modern, browser-native CSRF protection path by default, and token-heavy CSRF handling can gradually become the legacy compatibility path rather than the everyday developer experience.

The CSRF filter also adds Vary: Sec-Fetch-Site to normal shared responses, CSRF redirect responses, and CSRF exception responses for unsafe requests when Fetch Metadata protection is enabled, so caches do not mix responses across request contexts.

Tests cover same-origin, same-site, cross-site, token fallback, token-only compatibility, upgraded config compatibility, redirect responses, Vary behavior, and request body preservation.

References

Checklist:

  • Securely signed commits
  • Component(s) with PHPDoc blocks, only if necessary or adds value (without duplication)
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

- Add Fetch Metadata-first CSRF verification with token fallback.
- Keep upgraded apps token-only when the new config is missing.
- Add Vary handling for unsafe Fetch Metadata-protected requests.
- Document configuration, fallback behavior, and same-site caveats.
- Cover same-origin, same-site, cross-site, fallback, and filter behavior.

Signed-off-by: memleakd <121398829+memleakd@users.noreply.github.com>
@github-actions github-actions Bot added the 4.8 PRs that target the `4.8` branch. label May 20, 2026
Comment thread system/Filters/CSRF.php Outdated
Signed-off-by: memleakd <121398829+memleakd@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

4.8 PRs that target the `4.8` branch.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants