You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Nuxt.js中为Script和Link标签实现子资源完整性(SRI)以增强安全性?

解决方法

问题根因

  1. 文件路径错误:build:manifest钩子中asset.src是相对构建输出目录的路径,直接用readFile会找不到文件,必须拼接绝对路径才能读取到资源。
  2. manifest修改未关联HTML渲染:Nuxt 3默认不会自动读取manifest中的integrity属性并注入到最终HTML的<script>/<link>标签,需要额外处理HTML生成流程。

修改后的模块代码

import { createHash } from 'node:crypto'
import { readFile } from 'node:fs/promises'
import { resolve } from 'node:path'
import { defineNuxtModule } from '@nuxt/kit'

export interface ModuleOptions {
  enabled: boolean
  hash: string
  crossorigin: string
}

export default defineNuxtModule<ModuleOptions>({
  meta: {
    name: 'nuxt-sri',
    configKey: 'sri',
    compatibility: {
      nuxt: '^3.0.0',
    },
  },
  defaults: {
    enabled: true,
    hash: 'sha384',
    crossorigin: 'anonymous',
  },
  async setup(options, nuxt) {
    if (!options.enabled) return

    // 存储资源路径与SRI信息的映射
    const integrityMap = new Map()

    // 第一步:处理构建manifest,生成每个资源的SRI哈希
    nuxt.hook('build:manifest', async (manifest) => {
      const buildDir = nuxt.options.buildDir
      for (const [key, asset] of Object.entries(manifest)) {
        if (asset.src) {
          try {
            // 拼接资源的绝对路径
            const filePath = resolve(buildDir, asset.src)
            const data = await readFile(filePath)
            const hash = createHash(options.hash).update(data).digest('base64')
            const integrity = `${options.hash}-${hash}`
            
            integrityMap.set(asset.src, { integrity, crossorigin: options.crossorigin })
            // 同步更新manifest(可选,供其他依赖manifest的场景使用)
            asset.integrity = integrity
            asset.crossorigin = options.crossorigin
          } catch (error) {
            console.error('生成SRI哈希失败', asset.src, ':', error.message)
          }
        }
      }
    })

    // 第二步:修改HTML,给对应标签注入SRI属性
    nuxt.hook('vite:transformIndexHtml', async (html) => {
      // 处理script标签
      html = html.replace(/<script[^>]+src="([^"]+)"[^>]*>/g, (match, src) => {
        const info = integrityMap.get(src)
        if (info) {
          return match.replace(/>(?=<\/script>)/, ` integrity="${info.integrity}" crossorigin="${info.crossorigin}">`)
        }
        return match
      })

      // 处理stylesheet类型的link标签
      html = html.replace(/<link[^>]+href="([^"]+)"[^>]+rel="stylesheet"[^>]*>/g, (match, href) => {
        const info = integrityMap.get(href)
        if (info) {
          return match.replace(/>$/, ` integrity="${info.integrity}" crossorigin="${info.crossorigin}">`)
        }
        return match
      })

      return html
    })
  },
})

关键修改说明

  • 路径修正:用resolve(nuxt.options.buildDir, asset.src)拼接资源绝对路径,确保能正确读取构建后的文件。
  • HTML注入逻辑:通过vite:transformIndexHtml钩子直接修改生成的HTML,利用之前存储的映射表快速匹配资源并添加属性。
  • 映射存储优化:使用Map存储资源路径与SRI信息的对应关系,提升HTML处理阶段的查找效率。

验证方式

构建项目后,打开输出目录下的index.html,检查<script>和<link rel="stylesheet">标签是否已包含integrity和crossorigin属性。

内容的提问来源于stack exchange,提问作者Eliyas Hossain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 21:53:19