fastify/csrf-protection

GitHub: fastify/csrf-protection

Fastify 官方 CSRF 防护插件,为 Node.js Web 应用提供跨站请求伪造攻击的令牌生成与验证能力。

Stars: 168 | Forks: 20

# @fastify/csrf-protection [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/f44bfc8ebd155113.svg)](https://github.com/fastify/csrf-protection/actions/workflows/ci.yml) [![NPM version](https://img.shields.io/npm/v/@fastify/csrf-protection.svg?style=flat)](https://www.npmjs.com/package/@fastify/csrf-protection) [![neostandard javascript style](https://img.shields.io/badge/code_style-neostandard-brightgreen?style=flat)](https://github.com/neostandard/neostandard) 此插件帮助开发者保护其 Fastify 服务器免受 [CSRF](https://en.wikipedia.org/wiki/Cross-site_request_forgery) 攻击。 为了全面防御 CSRF,开发者应深入研究 [跨站请求伪造 (CSRF) 防护备忘单](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html)。 另请参阅 [pillarjs/understanding-csrf](https://github.com/pillarjs/understanding-csrf) 作为良好的指南。 ## 安全免责声明 保护应用程序免受 CSRF 攻击是_开发者的责任_,不应完全信任任何第三方模块。 我们不声明此模块能够在没有对 CSRF、其影响及所需缓解措施进行明确研究的情况下保护应用程序。 @fastify/csrf-protection 提供了一系列开发者可用于保护其应用程序的实用工具。 我们建议使用 [@fastify/helmet](https://github.com/fastify/fastify-helmet) 来实施其中一些缓解措施。 安全性始终是风险缓解、功能性、性能和开发者体验之间的权衡。 因此,只要此模块提供了通过配置实现完全缓解的方法,我们就不会将插件默认配置选项的报告视为在特定情况下可能不安全的安全漏洞。 ## 安装 ``` npm i @fastify/csrf-protection ``` ### 兼容性 | 插件版本 | Fastify 版本 | | ---------------|-----------------| | `>=7.x` | `^5.x` | | `>=4.x <7.x` | `^4.x` | | `^3.x` | `^3.x` | 请注意,如果某个 Fastify 版本已停止支持,那么上表中对应的该插件版本也将停止支持。 有关更多详细信息,请参阅 [Fastify 的 LTS 策略](https://github.com/fastify/fastify/blob/main/docs/Reference/LTS.md)。 ## 用法 ### 与 [`@fastify/cookie`](https://github.com/fastify/fastify-cookie) 配合使用 如果你将 `@fastify/csrf-protection` 与 `@fastify/cookie` 一起使用,CSRF 密钥将被添加到响应 cookies 中。 默认情况下,使用的 cookie 将被命名为 `_csrf`,但你可以通过 `cookieKey` 选项重命名它。 当提供 `cookieOpts` 时,它们将**覆盖**默认的 cookie 选项。请确保你恢复了任何提供合理且安全默认值的默认选项。 ``` 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 = reply.generateCsrf() return { token } } }) // protect a route fastify.route({ method: 'POST', path: '/', onRequest: fastify.csrfProtection, handler: async (req, reply) => { return req.body } }) ``` ### 与 [`@fastify/session`](https://github.com/fastify/session) 配合使用 如果你将 `@fastify/csrf-protection` 与 `@fastify/session` 一起使用,CSRF 密钥将被添加到 session 中。 默认情况下,使用的键将被命名为 `_csrf`,但你可以通过 `sessionKey` 选项重命名它。 ``` 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 = reply.generateCsrf() return { token } } }) // protect a route fastify.route({ method: 'POST', path: '/', onRequest: fastify.csrfProtection, handler: async (req, reply) => { return req.body } }) ``` ### 与 [`@fastify/secure-session`](https://github.com/fastify/fastify-secure-session) 配合使用 如果你将 `@fastify/csrf-protection` 与 `@fastify/secure-session` 一起使用,CSRF 密钥将被添加到 session 中。 默认情况下,使用的键将被命名为 `_csrf`,但你可以通过 `sessionKey` 选项重命名它。 ``` 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 = reply.generateCsrf() return { token } } }) // protect a route fastify.route({ method: 'POST', path: '/', onRequest: fastify.csrfProtection, handler: async (req, reply) => { return req.body } }) ``` ### 保护密钥安全 上面代码中显示的 `secret` 严格来说只是一个示例。在所有情况下,你都需要确保 `secret`: - **绝不**硬编码在代码、`.env` 文件或存储库中的任何地方 - 存储在某些外部服务中,如 KMS、Vault 或类似服务 - 在运行时读取并提供给此选项 - 具有足够的字符长度以提供充足的熵 - 是真正的随机字符序列(你可以使用 [crypto-random-string](https://npm.im/crypto-random-string)) 除了这些保护措施外,[为你的网站/应用使用 HTTPS](https://letsencrypt.org/) 对于避免 [MITM 攻击](https://en.wikipedia.org/wiki/Man-in-the-middle_attack) 等许多其他潜在安全问题极其重要。 ## API ### 模块选项 | 选项 | 描述 | | ----------- | ----------- | | `cookieKey` | 存储 CSRF 密钥的 cookie 名称,默认为 `_csrf`。 | | `cookieOpts` | cookie 序列化选项。参见 [@fastify/cookie](https://github.com/fastify/fastify-cookie)。 | | `sessionKey` | 在 session 中存储 CSRF 密钥的键名。 | | `getToken` | 用于从请求中获取 CSRF 密钥的同步函数。 | | `getUserInfo` | 用于获取用户特定信息字符串以防止 cookie 抛弃 (cookie tossing) 的同步函数。 | | `sessionPlugin` | 你正在使用的 session 插件(如果适用)。 | | `csrfOpts` | csrf 选项。参见 [@fastify/csrf](https://github.com/fastify/csrf)。 | | `logLevel` | `fastify.csrfProtection` 错误的日志级别。 | ### `reply.generateCsrf([opts])` 生成密钥(如果尚不存在)并返回一个 resolve 为关联密钥的 promise。 ``` const token = reply.generateCsrf() ``` 你也可以向该函数传递 [cookie 序列化](https://github.com/fastify/fastify-cookie) 选项。 如果在模块选项中指定了 `getUserInfo`,则 `userInfo` 选项是必需的。 提供的 `userInfo` 在 csrf token 内部经过哈希处理,不会直接暴露。 此选项是防止 cookie 抛弃所必需的。 如果在模块选项中指定了 `getUserInfo`,并且结合使用 [@fastify/cookie](https://github.com/fastify/fastify-cookie) 作为 sessionPlugin,则 `csrfOpts.hmacKey` 选项是必需的。 ### `fastify.csrfProtection(request, reply, next)` 一个钩子,你可以用来保护路由或整个插件免受 CSRF 攻击。 通常,我们建议使用 `onRequest` 钩子,但如果你通过请求体 (request body) 发送 token,则必须使用 `preValidation` 或 `preHandler` 钩子。 ``` // 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 } }) ``` 你可以通过 `getToken` 选项配置读取 CSRF token 的函数,默认使用以下内容: ``` 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'] } ``` 出于性能和[安全](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#use-of-custom-request-headers)原因,建议提供自定义的 `getToken` 函数。 ``` fastify.register(require('@fastify/csrf-protection'), { getToken: function (req) { return req.headers['csrf-token'] } } ) ``` 或者 ``` fastify.register(require('@fastify/csrf-protection'), { getToken: (req) => req.headers['csrf-token'] } ) ``` ## 许可证 根据 [MIT](./LICENSE) 授权。
标签:CSRF防护, Fastify, @fastify/csrf-protection, GNU通用公共许可证, HTTP安全, MITM代理, Node.js, Web安全, 中间件, 会话安全, 后端开发, 插件, 数据可视化, 暗色界面, 漏洞防御, 网络安全, 自定义脚本, 自定义脚本, 蓝队分析, 跨站请求伪造, 隐私保护