@dr.pogodin/csurf

中文文档
1.18.2发布于 2026/10/15MITTypeScriptES Module近 30 天下载 7.7万

ExpressJS 的 CSRF 代号中间软件

中文使用文档
文档目录10 节
  1. 贡献者
  2. 内容
  3. 中国证监会
  4. 安装
  5. API 密码
  6. csurf([选项])
  7. 实例
  8. 简单快递JS 示例
  9. 忽略路线
  10. 自定义错误处理

简历

Latest NPM Release NPM Downloads CircleCI GitHub Repo stars Dr. Pogodin Studio

节点.js 中国证监会 保护中间软件 运通JS。 。 。 .

Sponsor

贡献者


+ 原始贡献者 csurf


这是原作的叉子 库尔多夫 软件包被其作者以令人怀疑的推理而贬值(简言之,软件包是好的,但作者不想再维护它)。 向国家预防机制公布 @pogodin/ csurf 医生 :时,其版本 1.11.0 国家 完全匹配同样,最新版本的原始软件包,其版本始于 1.12.0 国家 将所有依赖性更新到最新版本,并根据需要进行错误维护。 从原始迁移 库尔多夫 将所有提及改为 @pogodin/ csurf 医生 :。 。 。 .


内容

中国证监会

编程 问题 ——如果浏览器知道一个认证 用于您的域名的 cookie, 它可能会连同所有 HTTP( S) 请求一起发送给您 后端, 请检查,页:1 即使那些自动触发 完全不相关的网站;从而允许恶意第三方制作 代表用户向您的 API 认证的请求,如果他已经装入 页面进入他的浏览器( p)即说. 坏演员不必知道这些饼干, 它可能只是依赖于用户的浏览器自动、直接发送到 你的API).

页:1 如果你选择了这个 (单位:千美元)SameSite=None - 坏主意),或者你的用户使用过时的,奇怪的 浏览器,直到最近 SameSite=None 默认饼干设置 (单位:千美元)譬如说. 克罗姆把它改成了 SameSite=Lax 仅在2020年) (中文(简体) ). 当然,选择这种默认行为的人(SameSite=None已经 之后又升到高级岗位 现在有六个数字教你 安全,而你们却陷于他们所造作的坑里即说. 他们选择 默认时,要铭记第三方 cookie 的应用程序,以及 他们没有想过这对可能的认证申请意味着什么 饼干).

防范企业社会责任基金的三个主要途径, (中文(简体) ), 简言之,所有资料都证实发起人 HTTP( S) 请求是您网站在用户运行的一部分( 合法与否) 浏览器, 即说. 它实际上能够读取(或写出)您的 cookie( 作为浏览器) 只允许前端访问来自同一来源的cookie). 请讲 hTTP( S) 请求中, 我们实际上假设您只使用 HTTP( S) —— 如果您 足够粗心 允许不安全的 HTTP 连接到你的后端, 你为什么关心CSRF?

  • 同步调试器模式 方法包括服务器为当前用户生成随机符号 会话,将其存储在服务器侧并传递到前端 与 HTML 页面一起。 要进行 API 请求, 需要前端 以读取该标志,并作为请求的一部分将其传回服务器 有效载荷,或在其标题。 服务器比较收到的符号值和 请求到该用户会话后端存储的值,如果 证明请求发起人是页面的一部分,能够 以读取该来源的 Cookie 集,或该用户实际使用的 HTML . 当然,在您的页面中注入了恶意代码( Name预算外)将有能力 也一样,从而绕过你的CSRF保护, 但是如果你允许的话 因此,没有必要担心中国SRF的保护 无论有没有它,你都完蛋了.

    当无时, CSRF 保护模式由此库提供 cookie 选项 已经设定。 执行起来也比较聪明, 而不是在服务器一侧存储发给用户的实际代币, 它生成,并为该用户存储随机密码密件 会话,然后用它来生成随机的,签名的符号,然后用它来生成 以 API 请求将这些指使符传递回服务器时验证 .

  • 自然双投递 Cookie 模式 方法包括服务器为当前用户生成随机符号 {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}然后把它传到前端 {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你应该知道 通过 饼干 做一个API 请求前端应该读取该符号,并将其传递回 服务器作为请求有效载荷的一部分,或在其标题中,而浏览器 在请求中还包括原始饼干。 服务器比较这些 两种符号值(在饼干中收到的,包含在 如果与请求的有效载荷或信头相符,则证明请求 发起者是页面的一部分,能够读取(或写)为此设定的饼干 源代码。 除了危险 预算外 如果一个坏角色 控制(或 预算外'es)是一个被保护域的子域,他将能够 打败它,因为他可以覆盖服务器为 保护域,从而绕过 CSRF 保护 请求自己的配对饼干(token)值.

    该库在 页:1 cookie 选项 设定 true此外,它也得到了一定的执行 不同的是,重复使用前一种模式所用的同一种代码和逻辑—— 它为用户会话产生随机的秘密(虽然它不是一个相当的秘密, 它不一定要在这个情景中,然后生成匹配的随机 代号,由那个秘密签名, 它把它们都送到前端 通过 两个不同的饼干。 要提出请求,前端应读作 这些饼干中的一款, 并把它纳入请求的有效载荷, 或标题。 收到请求时,服务器将确认收到该信使 在请求的有效载荷(标题)中,由所收到的秘密签名 通过 相应的饼干。 再说一遍,这个支票根本不靠这个 “秘密”是秘密,它只是在乎 是否“秘密” 和标志是匹配的对或不匹配的——它提供相同的 保护,如果前端刚刚通过 请求的“秘密” 值本身,直接与其在饼干中的值进行比较.

  • 已签名的双投递 Cookie 方法基本相同,但需要带符号的饼干 将在服务器侧签名和验证。 这样,即使一个坏演员 控制子域,从而能够覆盖符号饼干 ,它将被服务器检测到.

    该库在 页:1 cookie 选项 设置为带有 cookie 配置的对象 能够签署(signed 旗帜)。 由于执行的方式 (请求中的符号与存储在 其中一个饼干,其实是需要签名和防护的 对“秘密”饼干的修改 cookie 选项 实际应用。 而且,作为前端 不需要知道"秘密"发送请求, 选择也没用 HttpOnly, (中文(简体) ), secure和其他安全选项,尽管它并不完全 与这种保护方式有关.

剧情 a. 索赔的前后 库尔多夫 库开始于 “中国社会风险基金在大众社会风险保险一揽子方案中的脆弱性”。 。 。 . 问题是,安全“专家”写它并不完全 既不理解CSRF的保护,也不理解JavaScript,所以他才刚刚变得困惑 关于图书馆实施细节,请在上文作简要解释 基本上,他主张,只要简单 cookie: true 设置库 未正确执行 已签名的双投递 Cookie 保护,因为它没有在它设定的饼干上签名, 它没有保护 它不检查饼干的值 在随后的 API 请求中表示符号 。 的确,由于这种设定是正确的 执行 直肠双投饼干 保护,其局限性不影响大多数简单的网站.

这篇文章最后以一个误导性的说法结尾,图书开发者承认 并且因为它而使图书馆贬值 gitHub repo 中注解为“”由于 收到的大量安全脆弱性报告,其中大多数是: 利用公司社会责任基金本身的根本局限性。 捷运.js 项目没有资源投入这一模块,这主要是: 对现代基于SPA的应用来说是不必要的.- 基本上说 说"图书馆没事,但我们不想花时间回信" 给每个抱怨图书馆弱点的白痴,没有 理解这件事情.

在现实中,最危险的时刻是.. 鼓励原图书库,并重新播放关于互联网的文章 开发者从这个长期存在的 CSURF 库切换到许多新库之一 CSRF - 保护图书馆 由不同的人从头写作(他们不) 因此,你猜他们的能力水平 (见本主题)。 这都为依赖中毒创造了机会 (单位:千美元)即说. 有人用恶意代码创建了新的 CSRF 保护库 )或对诚实的错误(肯定的是,这个长期常设的图书馆 与任何新的替代方案相比. 这就是为什么这个叉 最初的CSURF 诞生—— 相反 我用新的替代品来尝试我的运气, 我刚刚造出了这个时间证明的图书馆, 审查了它的代码,以防万一,更新了依赖关系,并转换了源 代码库为TypeScript(只是为了便于未来的维护). 项目是 开放源码,因此,欢迎大家进一步审查,并提出任何建议 改进或修正.

安装

需要一个会话中间软件或 饼干派瑟 将首先初始化.

如果您对如何执行此模块有疑问, 请读 : 理解企业社会责任基金。 。 。 .

这是一个 节点.js 模块 npm 登记。安装使用 npm install 命令数字 :

$ npm install --save @dr.pogodin/csurf

API 密码

import csurf from '@dr.pogodin/csurf';

csurf([选项])

为 CSRF 符号创建和验证创建中间软件 。 这个中间软件 添加a req.csrfToken() 函数来制作一个符号,该符号应当添加到 请求在隐藏窗体字段、查询字符串等内进行变异. 此标志是针对访客的会话或csrf cookie验证的.

选项

这个 csurf 函数选择 options 可能包含的对象 下列任何一键:

确定用户的令牌秘密是否应该存储在饼干中 或进入 req.session. 将标志性的秘密放入饼干工具 页:1 双重提交 cookie 模式。 。 。 . 默认为 false。 。 。 .

设定为 true (或饼干的选项对象),然后是模块 改变行为而不再使用 req.session这意味着你 没有 更长时间使用会话中间软件相反,你确实需要使用 饼干派瑟 中间软件 你的应用程序在这中间软件之前.

当设定到对象时,可以启用密钥的 cookie 存储和 对象包含此功能的选项( 当设定为 true,则 使用选项的默认值)。 备选方案可包含其中任何一项 以下键 :

  • key - 用于存储象征秘密的饼干名称 (违约) '_csrf') (中文(简体) ).
  • path - 饼干的路径(默认为 '/') (中文(简体) ).
  • signed - 表示是否应该签名(默认为: false) (中文(简体) ).
  • secure - 标记只用于 HTTPS 的饼干( 默认为 false) (中文(简体) ).
  • maxAge - 饼干过期的秒数 (默认会话长度).
  • httpOnly - 标记饼干,只供网络服务器访问 (违约) false) (中文(简体) ).
  • sameSite - 为饼干设置相同的站点策略( 默认为) false) (中文(简体) ). 这可以设定为 'strict', (中文(简体) ), 'lax', (中文(简体) ), 'none',或 true (地图到 'strict') (中文(简体) ).
  • domain - 设置 cookie 有效的域名( 默认为当前) 页:1.
忽略方法

CSRF 符号检查将禁用的一系列方法 . 默认为 ['GET', 'HEAD', 'OPTIONS']。 。 。 .

忽略请求

带有标志的可选函数 (req: Request) => boolean。 。 。 . 如果提供了, 则每个导致此结果的请求都会跳过 CSRF 令牌检查 要返回的函数 真实。 。 。 .

会话

确定哪些属性(“ 键 ”) req 会话对象位于此处. 默认为 'session' (即观察) req.session) (中文(简体) ). 中国证监会的秘密 从此库存储并读取为 req[sessionKey].csrfSecret。 。 。 .

如果 "饼干"选项 没有 false,然后此选项会 没什么.

价值

提供中间软件将引用的函数,以读取从 请求审定。 该功能称为 value(req) 已经 以字符串的形式返回符号 .

默认值是读取符号的函数 : 地点,顺序:

  • req.body._csrf - 通常由 body-parser 模块.
  • req.query._csrf 从 Express.js 读取 URL 的内置 查询字符串.
  • req.headers['csrf-token'] - 那个 CSRF-Token HTTP 请求头 .
  • req.headers['xsrf-token'] - 那个 XSRF-Token HTTP 请求头 .
  • req.headers['x-csrf-token'] - 那个 X-CSRF-Token HTTP 请求头 .
  • req.headers['x-xsrf-token'] - 那个 X-XSRF-Token HTTP 请求头 .

实例

简单快递JS 示例

以下是一些生成窗体的服务器侧代码的示例 这需要一个CSRF的标志 发回.

import cookieParser from 'cookie-parser';
import csrf from '@dr.pogodin/csurf';
import bodyParser from 'body-parser';
import express from 'express';

// setup route middlewares
const csrfProtection = csrf({ cookie: true })
const parseForm = bodyParser.urlencoded({ extended: false })

// create express app
const app = express()

// parse cookies
// we need this because "cookie" is true in csrfProtection
app.use(cookieParser())

app.get('/form', csrfProtection, function (req, res) {
  // pass the csrfToken to the view
  res.render('send', { csrfToken: req.csrfToken() })
})

app.post('/process', parseForm, csrfProtection, function (req, res) {
  res.send('data is being processed')
})

视图内部( 取决于模板语言; 手提栏样式) ),设置 csrfToken 值为隐藏的值 命名输入字段 _csrf数字 :

<form action="/process" method="POST">
  <input type="hidden" name="_csrf" value="{{csrfToken}}">
  
  Favorite color: <input type="text" name="favoriteColor">
  <button type="submit">Submit</button>
</form>

使用 AJAX

当通过 ajax 访问受保护的路由时, csrf 符号需要为 在请求中通过。 通常使用请求页眉进行, 如添加 请求信头通常可以在中心位置进行,而不需要 有效载荷修改.

中国证监会的令牌来自 req.csrfToken() 呼叫服务器侧. 这个信使需要暴露在客户端,一般通过将其包含在 初始页面内容。 一种可能性是在 HTML 中存储 <meta> 标签, ,然后在 JavaScript 请求时检索到值.

以下内容可以包含在您的观点中(下面的手列示例),其中 csrfToken 值来自 req.csrfToken()数字 :

<meta name="csrf-token" content="{{csrfToken}}">

下面是使用下列方法的例子: 获取 API 员额 页:1 /process 带有 CSRF 符号的路由 <meta> 页面标签 :

// Read the CSRF token from the <meta> tag
var token = document.querySelector('meta[name="csrf-token"]').getAttribute('content')

// Make a request using the Fetch API
fetch('/process', {
  credentials: 'same-origin', // <-- includes cookies in the request
  headers: {
    'CSRF-Token': token // <-- is the csrf token as a header
  },
  method: 'POST',
  body: {
    favoriteColor: 'blue'
  }
})

单页应用程序( SPA)

许多SPA框架如Angular有CSRF支持自动构建. 通常它们会反映 特定饼干的价值,比如 XSRF-TOKEN (此为角相也.

为了利用这一点,设定值来自 req.csrfToken() 在饼干中 由SPA框架使用。 只要在这条路线上 制作页面( 在 res.render 或者说 res.sendFile 在"快车"里叫着, (例如,a/cn.9/wg.iii/wp.iii/wp.1号文件).

以下是典型SPA反应的快递:

app.all('*', function (req, res) {
  res.cookie('XSRF-TOKEN', req.csrfToken())
  res.render('index')
})

忽略路线

说明 CSRF 检查应只针对您期望的请求而禁用 来源于您的网站。 不禁用 CSRF 检查请求 您希望只来自您的网站。 现有会话,即使 它属于经认证的用户,不足以防范CSRF 攻击.

以下是如何命令您的路线的示例, 这样某些端点 不检查有效的 CSRF 令牌 .

import cookieParser from 'cookie-parser';
import csrf from '@dr.pogodin/csurf';
import bodyParser from 'body-parser';
import express from 'express';

// create express app
const app = express()

// create api router
const api = createApiRouter()

// mount api before csrf is appended to the app stack
app.use('/api', api)

// now add csrf and other middlewares, after the "/api" was mounted
app.use(bodyParser.urlencoded({ extended: false }))
app.use(cookieParser())
app.use(csrf({ cookie: true }))

app.get('/form', function (req, res) {
  // pass the csrfToken to the view
  res.render('send', { csrfToken: req.csrfToken() })
})

app.post('/process', function (req, res) {
  res.send('csrf was required to get here')
})

function createApiRouter () {
  const router = new express.Router()

  router.post('/getProfile', function (req, res) {
    res.send('no csrf to get here')
  })

  return router
}

自定义错误处理

当 CSRF 令牌验证失败时, 就会出现错误 err.code === 'EBADCSRFTOKEN'。这可用于显示自定义 错误消息 .

import bodyParser from 'body-parser';
import cookieParser from 'cookie-parser';
import csrf from '@dr.pogodin/csurf';
import express from 'express';

const app = express()
app.use(bodyParser.urlencoded({ extended: false }))
app.use(cookieParser())
app.use(csrf({ cookie: true }))

// error handler
app.use(function (err, req, res, next) {
  if (err.code !== 'EBADCSRFTOKEN') return next(err)

  // handle CSRF token errors here
  res.status(403)
  res.send('form tampered with')
})

版本与发布记录

@dr.pogodin/csurf 共发布 25 个版本,首次发布于 2022/11/05;过去 12 个月发布了 7 个版本。

版本发布日期距今
1.18.2latest2026/10/1529 天前
1.18.12026/09/221 个月前
1.17.12026/06/075 个月前
1.17.02026/05/315 个月前
1.16.92026/03/217 个月前
1.16.82026/01/149 个月前

关于 @dr.pogodin/csurf 的常见问题

@dr.pogodin/csurf 是什么?

ExpressJS 的 CSRF 代号中间软件

如何安装 @dr.pogodin/csurf?

在项目目录运行 npm install @dr.pogodin/csurf,或使用 pnpm add / yarn add / bun add。

@dr.pogodin/csurf 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@dr.pogodin/csurf 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@dr.pogodin/csurf 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@dr.pogodin/csurf 可以商用吗?

@dr.pogodin/csurf 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@dr.pogodin/csurf 的下载量有多少?

根据 npm 官方下载统计,@dr.pogodin/csurf 在 2026/10/13 – 2026/11/11 这 30 天内被下载 76,717 次,日均约 2,557 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@dr.pogodin/csurf 还在维护吗?

最新版本 1.18.2 发布于 2026/10/15(29 天前);至今共发布 25 个版本,其中过去 12 个月发布了 7 个;首次发布于 2022/11/05。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。