File size: 1,484 Bytes
788eab4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
"""

Cross-Site Request Forgery (CSRF) Protection.

Provides cryptographically secure anti-CSRF token generation and validation.

"""

from __future__ import annotations

import hmac
import secrets

from fastapi import HTTPException, Request, status

CSRF_COOKIE_NAME = "csrf_token"
CSRF_HEADER_NAME = "X-CSRF-Token"


def generate_csrf_token() -> str:
    """Generates a high-entropy URL-safe CSRF token."""
    return secrets.token_urlsafe(32)


def verify_csrf_token(request: Request) -> None:
    """

    Validates CSRF token on state-mutating requests (POST, PUT, DELETE, PATCH).

    Excludes initial authentication endpoints that issue tokens.

    """
    if request.method in ("GET", "HEAD", "OPTIONS"):
        return

    # Skip login and initial auth routes
    if request.url.path in ("/api/auth/login", "/api/auth/student-login", "/api/auth/csrf"):
        return

    cookie_token = request.cookies.get(CSRF_COOKIE_NAME)
    header_token = request.headers.get(CSRF_HEADER_NAME)

    if not cookie_token or not header_token:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="CSRF token missing from request cookie or header.",
        )

    if not hmac.compare_digest(cookie_token, header_token):
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="CSRF token mismatch. Potential cross-site request forgery rejected.",
        )