Skip to content

CSRF 防护

该中间件通过校验 OriginSec-Fetch-Site 请求头来抵御 CSRF 攻击,只要其中任一校验通过即可放行。

中间件仅会对以下请求进行校验:

  • 使用不安全 HTTP 方法(非 GET、HEAD、OPTIONS)
  • Content-Type 为 HTML 表单可发送的类型(application/x-www-form-urlencodedmultipart/form-datatext/plain

旧版浏览器可能不会发送 Origin 头,或运行在移除了这些头部的反向代理环境中,此时该中间件效果会受限,建议改用其他基于 CSRF Token 的方案。

导入

ts
import { Hono } from 'hono'
import { csrf } from 'hono/csrf'

用法

ts
const app = new Hono()

// 默认同时验证 origin 与 sec-fetch-site
app.use(csrf())

// 允许特定来源
app.use(csrf({ origin: 'https://myapp.example.com' }))

// 允许多个来源
app.use(
  csrf({
    origin: [
      'https://myapp.example.com',
      'https://development.myapp.example.com',
    ],
  })
)

// 允许指定的 sec-fetch-site 值
app.use(csrf({ secFetchSite: 'same-origin' }))
app.use(csrf({ secFetchSite: ['same-origin', 'none'] }))

// 动态校验来源
// 强烈建议验证协议并确保以 `$` 结尾匹配。
// 切勿使用前缀匹配。
app.use(
  '*',
  csrf({
    origin: (origin) =>
      /https:\/\/(\w+\.)?myapp\.example\.com$/.test(origin),
  })
)

// 动态校验 sec-fetch-site
app.use(
  csrf({
    secFetchSite: (secFetchSite, c) => {
      // 始终允许同源请求
      if (secFetchSite === 'same-origin') return true
      // 为 webhook 端点允许跨站请求
      if (
        secFetchSite === 'cross-site' &&
        c.req.path.startsWith('/webhook/')
      ) {
        return true
      }
      return false
    },
  })
)

选项

optional origin:string | string[] | Function

指定允许通过 CSRF 校验的来源:

  • string:单个允许来源(例如 'https://example.com'
  • string[]:允许来源组成的数组
  • Function:自定义处理函数 (origin: string, context: Context) => boolean,可灵活编写校验或放行逻辑

默认值:仅允许与请求 URL 同源。

函数会收到请求头中的 Origin 值与当前请求的上下文,可基于路径、请求头或其他上下文信息进行动态判断。

optional secFetchSite:string | string[] | Function

利用 Fetch Metadata 机制,指定允许通过 CSRF 校验的 Sec-Fetch-Site 请求头:

  • string:单个允许值(例如 'same-origin'
  • string[]:允许值数组(例如 ['same-origin', 'none']
  • Function:自定义处理函数 (secFetchSite: string, context: Context) => boolean

默认值:仅允许 'same-origin'

常见的 Sec-Fetch-Site 取值:

  • same-origin:来自同源的请求
  • same-site:来自同站点(不同子域)的请求
  • cross-site:来自不同站点的请求
  • none:非网页发起的请求(例如地址栏或书签)

该函数会收到请求头中的 Sec-Fetch-Site 值及上下文,可据此动态判断是否允许。

Released under the MIT License.