CSRF Protection
Cross-Site Request Forgery (CSRF) is a type of malicious exploit of a website where unauthorized commands are transmitted from a user that the web application trusts. The Blocklet SDK provides a robust middleware to protect your Blocklet application from such attacks. This middleware automatically handles the generation and verification of CSRF tokens, ensuring that requests originate from legitimate sources.
For an overview of all available middleware, refer to the Middleware Reference section.
csrf
Middleware#
The csrf
middleware is designed to be integrated into your Express.js application to automatically manage CSRF protection. It intercepts incoming requests, generates a token for GET
requests, and verifies the token for state-changing requests (POST
, PUT
, PATCH
, DELETE
).
export function csrf(
options: CSRFOptions = { generateToken: defaultGenerateToken, verifyToken: defaultVerifyToken }
): RequestHandler;
export interface CSRFOptions {
generateToken?: (req: Request, res: CSRFOptionsResponse) => void | Promise<void>;
verifyToken?: (req: Request, res: CSRFOptionsResponse) => Promise<void> | void;
}
export interface CSRFOptionsResponse
extends Response<
any,
{ generateToken: typeof defaultGenerateToken; verifyToken: typeof defaultVerifyToken } & Record<string, any>
> {}
Parameters
Name | Type | Description | Default |
---|---|---|---|
|
| Optional configuration object to customize token generation and verification logic. |
|
Middleware Behavior
The csrf
middleware operates based on the HTTP method of the incoming request:
- For
GET
requests: It attempts to generate and set anx-csrf-token
cookie on the client's browser. This token is derived from thelogin_token
cookie, if present. - For
POST
,PUT
,PATCH
, orDELETE
requests: It attempts to verify thex-csrf-token
header sent by the client against thex-csrf-token
cookie. If the tokens do not match or the signature is invalid, an error is thrown, preventing the request from proceeding. Verification is skipped for requests originating from a DID Wallet Connect. - For other request methods (e.g.,
HEAD
,OPTIONS
): The middleware proceeds to the next middleware without performing any token generation or verification.
Flow Diagram#
The following diagram illustrates the operational flow of the csrf
middleware:
Default Token Generation (defaultGenerateToken
)#
This function is used by default to generate the CSRF token. It requires the cookie-parser
middleware to be installed for proper operation.
Parameters
Name | Type | Description |
---|---|---|
|
| The Express request object. |
|
| The Express response object. |
Behavior
If req.cookies.login_token
exists and req.cookies['x-csrf-token']
does not, it generates a new x-csrf-token
using a double hmac
of the login_token
and sets it as a secure, sameSite: 'none'
cookie. This token consists of two parts: the MD5 hash and its signed version, separated by a dot.
import { csrf } from '@blocklet/sdk/middlewares';
function defaultGenerateToken(req, res) {
// ... internal logic ...
if (req.cookies.login_token && !req.cookies['x-csrf-token']) {
const xCsrfTokenMd5 = hmac(req.cookies.login_token);
const xCsrfTokenSigned = hmac(xCsrfTokenMd5);
res.cookie('x-csrf-token', [xCsrfTokenMd5, xCsrfTokenSigned].join('.'), {
sameSite: 'none',
secure: true,
});
}
}
Default Token Verification (defaultVerifyToken
)#
This function is used by default to verify the CSRF token for state-changing requests. It also requires the cookie-parser
middleware.
Parameters
Name | Type | Description |
---|---|---|
|
| The Express request object. |
Behavior
It compares the x-csrf-token
from req.cookies
with the x-csrf-token
from req.headers
. If they match and the hmac
signature embedded within the token is valid, the request is allowed to proceed. Otherwise, it throws an Error('Invalid request: csrf token mismatch')
.
import { csrf } from '@blocklet/sdk/middlewares';
function defaultVerifyToken(req) {
// ... internal logic ...
if (
req.cookies &&
!isEmpty(req.cookies['x-csrf-token']) &&
req.cookies['x-csrf-token'] === req.headers['x-csrf-token']
) {
const [xCsrfTokenMd5, xCsrfTokenSigned] = (req.headers['x-csrf-token'] as string).split('.');
if (hmac(xCsrfTokenMd5 as string) === xCsrfTokenSigned) {
return; // Token is valid
}
}
throw new Error('Invalid request: csrf token mismatch');
}
Usage Example#
To use the CSRF protection middleware in your Blocklet application, typically you would include it after the cookie-parser
and session
middlewares.
import express from 'express';
import cookieParser from 'cookie-parser';
import { csrf, session } from '@blocklet/sdk/middlewares';
const app = express();
app.use(cookieParser());
app.use(session()); // Session middleware is often needed before CSRF
app.use(csrf()); // Use the CSRF middleware
// Example route to demonstrate token generation
app.get('/', (req, res) => {
res.send('Welcome! CSRF token should be in your cookies.');
});
// Example route to demonstrate token verification
app.post('/submit', (req, res) => {
res.send('Form submitted successfully with valid CSRF token.');
});
// Error handling middleware (optional, but recommended)
app.use((err, req, res, next) => {
if (err.message === 'Invalid request: csrf token mismatch') {
return res.status(403).send('CSRF Token Mismatch. Forbidden.');
}
next(err);
});
app.listen(3000, () => {
console.log('Blocklet app listening on port 3000');
});
This example sets up a basic Express application with the csrf
middleware. GET
requests will receive a CSRF token in their cookies, and POST
requests will require a valid x-csrf-token
header for successful processing.
This section detailed the CSRF protection middleware, explaining its functionality for securing your Blocklet application. Continue to the Blocklet/Component Signature section to learn about middleware for verifying digital signatures from other Blocklets or components.