CSRF protection
CSRF (Cross-Site Request Forgery) is an attack in which a malicious website tricks the users of your web app to perform form submissions without their explicit consent.
To protect against CSRF attacks, you should define a hidden input field holding the CSRF token value that only your website can generate and verify.
Configuration
Any route configured with the web middleware group will automatically have
CSRF protection enabled.
If you want to configure a specific route with CSRF protection, you can use the ValidateCSRFToken middleware:
The ValidateCSRFToken middleware requires that a session store has been configured.
As such you should also add the LoadSession middleware to the route.
from expanse.session.middleware.load_session import LoadSession
from expanse.session.middleware.validate_csrf_token import ValidateCSRFToken
router.post('/profile', ...).middleware(LoadSession, ValidateCSRFToken)
Protecting forms
As mentioned earlier, you should include a hidden input field in your forms to hold the CSRF token value.
This may be done using the csrf_token helper function inside your templated:
<form method="POST" action="/">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<input type="name" name="name" placeholder="Enter your name">
<button type="submit">Submit</button>
</form>
During the form submission, the ValidateCSRFToken middleware will automatically validate the _token token,
only allowing the form submissions with a valid CSRF token.
Handling errors
If the CSRF token validation fails, the ValidateCSRFToken middleware will throw a CSRFTokenMismatchError exception.
By default, this exception will be caught by the framework and a 419 Page Expired response will be returned.
If you'd like to customize the error handling, you override the default error handler in your AppServiceProvider:
from expanse.contracts.debug.exception_handler import ExceptionHandler
from expanse.core.http.exceptions import HTTPException
from expanse.session.exceptions import CSRFTokenMismatchError
from expanse.support.service_provider import ServiceProvider
class AppServiceProvider(ServiceProvider):
async def boot(self, handler: ExceptionHandler) -> None:
handler.prepare_using(
CSRFTokenMismatchError,
self.handle_csrf_token_mismatch
)
def handle_csrf_token_mismatch(
self, error: CSRFTokenMismatchError
) -> HTTPException:
return HTTPException(403, str(error))
Using the X-CSRF-TOKEN header
In addition to checking for the CSRF token as a POST parameter for forms, the ValidateCSRFToken middleware will also
check for a X-CSRF-TOKEN request header.
Using the X-XSRF-TOKEN header
Expanse stores the current CSRF token in an encrypted XSRF-TOKEN cookie that is included with each response generated
by the framework. This cookie can be read by the frontend JavaScript and used to set the X-XSRF-TOKEN header on
subsequent requests.
This allows frontend request libraries like Axios to read the XSRF-TOKEN automatically and set it as a X-XSRF-TOKEN
header when making Ajax requests without server-rendered forms.
The XSRF-TOKEN cookie will be encrypted if — and only if — the EncryptCookies middleware is enabled for the
route matching the request. This is the default behavior for the web middleware group.