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

Laravel+Vue+Vite项目中为Vue注入的内联样式/脚本添加CSP Nonce

问题描述

我有一个基于Vite的Laravel与Vue同仓库项目,已经通过spatie/laravel-csp实现了内容安全策略(CSP),浏览器检查显示script-src和style-src的nonce已成功生成,但出现以下两个错误:

  1. the 'unsafe-inline' keyword, a hash ('sha256-nMxMqdZhkHxz5vAuW/PAoLvECzzsmeAxD/BNwG15HuA='), or a nonce ('nonce-...') is required to enable inline execution. Note that hashes do not apply to event handlers, style attributes and javascript: navigations unless the 'unsafe-hashes' keyword is present.
  2. Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' 'nonce-H1R2LrVAcuLDIUMAB8wqwBzBFstVEppy'"

我推测是Vue注入的内联样式和脚本未携带nonce导致的问题,该如何解决?

以下是我的自定义Policy代码:

<?php

namespace App\Support\Csp\Policies;

use Spatie\Csp\Directive;
use Spatie\Csp\Policies\Basic;

class CustomPolicy extends Basic
{
  public function configure()
  {
    parent::configure();

    $this->addDirective(Directive::FONT, ['fonts.gstatic.com'])
      ->addDirective(Directive::STYLE, ['https://fonts.googleapis.com'])
      ->addDirective(Directive::IMG, ['data:']);
  }
}

解决方案

1. 解决内联脚本/样式的nonce缺失问题

Vue开发环境会动态注入内联脚本和样式,Vite的客户端入口脚本也得带nonce才能通过CSP校验。要让Laravel把生成的nonce传递给Vite,让它自动给注入的资源带上nonce:

第一步:在Blade模板里给Vite传nonce

修改主Blade视图(比如resources/views/app.blade.php),调用@vite时加上nonce参数:

<head>
    <!-- 其他头部内容 -->
    @vite(['resources/js/app.js'], ['nonce' => csp_nonce()])
</head>

csp_nonce()是spatie/laravel-csp提供的辅助函数,直接获取当前请求生成的nonce即可。

第二步:确保CSP的style-src包含nonce

你当前的Policy里style-src只添加了谷歌字体,要保证它包含自动生成的nonce。Basic策略默认已经包含nonce,但如果手动覆盖了style-src,需要显式添加:

$this->addDirective(Directive::STYLE, [
    'https://fonts.googleapis.com',
    "'nonce-" . csp_nonce() . "'"
]);

更省心的方式是直接用addDirective在原有基础上追加,因为Basic策略本身已经包含了'self'和nonce,无需手动添加,除非你清空了原有指令。

2. 解决unsafe-eval错误

Vue开发环境会用eval实现热更新和响应式调试,所以得在CSP的script-src里添加'unsafe-eval'。生产环境下Vue会编译成纯JS,不需要这个配置,所以按环境区分处理:

修改CustomPolicy:

public function configure()
{
    parent::configure();

    $this->addDirective(Directive::FONT, ['fonts.gstatic.com'])
        ->addDirective(Directive::STYLE, ['https://fonts.googleapis.com'])
        ->addDirective(Directive::IMG, ['data:']);

    // 仅开发环境添加unsafe-eval
    if (app()->environment('local')) {
        $this->addDirective(Directive::SCRIPT, "'unsafe-eval'");
    }
}

额外提醒

  • 生产部署前确认Vite已经完成构建,这时Vue不会生成内联脚本/样式,也不需要unsafe-eval,可以移除相关配置。
  • 如果仍有内联样式报错,检查组件中是否使用了style属性(内联样式),这种情况要么给style-src添加'unsafe-hashes'和对应的哈希值,要么改用CSS类控制样式。示例:
$this->addDirective(Directive::STYLE, [
    'https://fonts.googleapis.com',
    "'unsafe-hashes'",
    "'sha256-nMxMqdZhkHxz5vAuW/PAoLvECzzsmeAxD/BNwG15HuA='"
]);

优先推荐用CSS类替代内联样式。


内容的提问来源于stack exchange,提问作者Alphy Gacheru

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 19:47:26