如何在Nuxt.js中为Script和Link标签实现子资源完整性(SRI)以增强安全性?
解决方法
问题根因
- 文件路径错误:
build:manifest钩子中asset.src是相对构建输出目录的路径,直接用readFile会找不到文件,必须拼接绝对路径才能读取到资源。 - 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
相关产品推荐
相关产品推荐

