Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/fastify/fastify-csrf
A fastify csrf plugin.
https://github.com/fastify/fastify-csrf
csrf csrf-protection fastify fastify-plugin
Last synced: 3 months ago
JSON representation
A fastify csrf plugin.
- Host: GitHub
- URL: https://github.com/fastify/fastify-csrf
- Owner: fastify
- License: other
- Created: 2019-01-07T07:09:39.000Z (almost 6 years ago)
- Default Branch: master
- Last Pushed: 2024-04-14T09:27:21.000Z (7 months ago)
- Last Synced: 2024-05-13T05:09:30.130Z (6 months ago)
- Topics: csrf, csrf-protection, fastify, fastify-plugin
- Language: JavaScript
- Homepage:
- Size: 177 KB
- Stars: 134
- Watchers: 17
- Forks: 15
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-nodejs-security - fastify-csrf - A plugin for adding CSRF protection to [fastify](https://www.fastify.io). (CSRF)
README
# @fastify/csrf-protection
![CI](https://github.com/fastify/csrf-protection/workflows/CI/badge.svg)
[![NPM version](https://img.shields.io/npm/v/@fastify/csrf-protection.svg?style=flat)](https://www.npmjs.com/package/@fastify/csrf-protection)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://standardjs.com/)This plugin helps developers protect their Fastify server against [CSRF](https://en.wikipedia.org/wiki/Cross-site_request_forgery) attacks.
In order to fully protect against CSRF, developers should study [Cross-Site Request Forgery Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html)
in depth. See also [pillarjs/understanding-csrf](https://github.com/pillarjs/understanding-csrf) as a good guide.## Security Disclaimer
Securing applications against CSRF is a _developer responsibility_ and it should not be fully trusted to any third party modules.
We do not claim that this module is able to protect an application without a clear study of CSRF, its impact and the needed mitigations.
@fastify/csrf-protection provides a series of utilities that developers can use to secure their application.
We recommend using [@fastify/helmet](https://github.com/fastify/fastify-helmet) to implement some of those mitigations.Security is always a tradeoff between risk mitigation, functionality, performance, and developer experience.
As a result we will not consider a report of a plugin default configuration option as security
vulnerability that might be unsafe in certain scenarios as long as this module provides a
way to provide full mitigation through configuration.# Install
```js
npm i @fastify/csrf-protection
```## Usage
### Use with [`@fastify/cookie`](https://github.com/fastify/fastify-cookie)
If you use `@fastify/csrf-protection` with `@fastify/cookie`, the CSRF secret will be added to the response cookies.
By default, the cookie used will be named `_csrf`, but you can rename it via the `cookieKey` option.
When `cookieOpts` are provided, they **override** the default cookie options. Make sure you restore any of the default options which provide sensible and secure defaults.```js
fastify.register(require('@fastify/cookie'))
fastify.register(require('@fastify/csrf-protection'))// if you want to sign cookies:
fastify.register(require('@fastify/cookie'), { secret }) // See following section to ensure security
fastify.register(require('@fastify/csrf-protection'), { cookieOpts: { signed: true } })// generate a token
fastify.route({
method: 'GET',
path: '/',
handler: async (req, reply) => {
const token = await reply.generateCsrf()
return { token }
}
})// protect a route
fastify.route({
method: 'POST',
path: '/',
onRequest: fastify.csrfProtection,
handler: async (req, reply) => {
return req.body
}
})
```### Use with [`@fastify/session`](https://github.com/fastify/session)
If you use `@fastify/csrf-protection` with `@fastify/session`, the CSRF secret will be added to the session.
By default, the key used will be named `_csrf`, but you can rename it via the `sessionKey` option.```js
fastify.register(require('@fastify-session'), { secret: "a string which is longer than 32 characters" })
fastify.register(require('@fastify/csrf-protection'), { sessionPlugin: '@fastify/session' })// generate a token
fastify.route({
method: 'GET',
path: '/',
handler: async (req, reply) => {
const token = await reply.generateCsrf()
return { token }
}
})// protect a route
fastify.route({
method: 'POST',
path: '/',
onRequest: fastify.csrfProtection,
handler: async (req, reply) => {
return req.body
}
})
```### Use with [`@fastify/secure-session`](https://github.com/fastify/fastify-secure-session)
If you use `@fastify/csrf-protection` with `@fastify/secure-session`, the CSRF secret will be added to the session.
By default, the key used will be named `_csrf`, but you can rename it via the `sessionKey` option.```js
fastify.register(require('@fastify/secure-session'), { secret: "a string which is longer than 32 characters" })
fastify.register(require('@fastify/csrf-protection'), { sessionPlugin: '@fastify/secure-session' })// generate a token
fastify.route({
method: 'GET',
path: '/',
handler: async (req, reply) => {
const token = await reply.generateCsrf()
return { token }
}
})// protect a route
fastify.route({
method: 'POST',
path: '/',
onRequest: fastify.csrfProtection,
handler: async (req, reply) => {
return req.body
}
})
```### Securing the secret
The `secret` shown in the code above is strictly just an example. In all cases, you would need to make sure that the `secret` is:
- **Never** hard-coded in the code or `.env` files or anywhere in the repository
- Stored in some external services like KMS, Vault or something similar
- Read at run-time and supplied to this option
- Of significant character length to provide adequate entropy
- Truly random sequence of characters (You could use [crypto-random-string](https://npm.im/crypto-random-string))Apart from these safeguards, it is extremely important to [use HTTPS for your website/app](https://letsencrypt.org/) to avoid a bunch of other potential security issues like [MITM attacks](https://en.wikipedia.org/wiki/Man-in-the-middle_attack) etc.
## API
### Module Options
| Options | Description |
| ----------- | ----------- |
| `cookieKey` | The name of the cookie where the CSRF secret will be stored, default `_csrf`. |
| `cookieOpts` | The cookie serialization options. See [@fastify/cookie](https://github.com/fastify/fastify-cookie). |
| `sessionKey` | The key where to store the CSRF secret in the session. |
| `getToken` | A sync function to get the CSRF secret from the request. |
| `getUserInfo` | A sync function to get the a string of user-specific information to prevent cookie tossing. |
| `sessionPlugin` | The session plugin that you are using (if applicable). |
| `csrfOpts` | The csrf options. See [@fastify/csrf](https://github.com/fastify/csrf). |### `reply.generateCsrf([opts])`
Generates a secret (if it is not already present) and returns a promise that resolves to the associated secret.
```js
const token = await reply.generateCsrf()
```You can also pass the [cookie serialization](https://github.com/fastify/fastify-cookie) options to the function.
The option `userInfo` is required if `getUserInfo` has been specified in the module option.
The provided `userInfo` is hashed inside the csrf token and it is not directly exposed.
This option is needed to protect against cookie tossing.
The option `csrfOpts.hmacKey` is required if `getUserInfo` has been specified in the module option in combination with using [@fastify/cookie](https://github.com/fastify/fastify-cookie) as sessionPlugin### `fastify.csrfProtection(request, reply, next)`
A hook that you can use for protecting routes or entire plugins from CSRF attacks.
Generally, we recommend using an `onRequest` hook, but if you are sending the token
via the request body, then you must use a `preValidation` or `preHandler` hook.```js
// protect the fastify instance
fastify.addHook('onRequest', fastify.csrfProtection)// protect a single route
fastify.route({
method: 'POST',
path: '/',
onRequest: fastify.csrfProtection,
handler: async (req, reply) => {
return req.body
}
})
```You can configure the function to read the CSRF token via the `getToken` option, by default the following is used:
```js
function getToken (req) {
return (req.body && req.body._csrf) ||
req.headers['csrf-token'] ||
req.headers['xsrf-token'] ||
req.headers['x-csrf-token'] ||
req.headers['x-xsrf-token']
}
```It is recommended to provide a custom `getToken` function for performance and [security](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#use-of-custom-request-headers) reasons.
```js
fastify.register(require('@fastify/csrf-protection'),
{ getToken: function (req) { return req.headers['csrf-token'] } }
)
```
or```js
fastify.register(require('@fastify/csrf-protection'),
{ getToken: (req) => req.headers['csrf-token'] }
)
```## License
[MIT](./LICENSE)