主题
CSP (内容安全策略) 构建
Livewire 提供了一个 CSP 安全的构建版本,允许您在禁止 'unsafe-eval' 的严格内容安全策略 (CSP) 环境中使用 Livewire 应用程序。
什么是内容安全策略 (CSP)?
内容安全策略 (CSP) 是一种安全标准,有助于防止各种类型的攻击,包括跨站脚本 (XSS) 和代码注入攻击。CSP 通过允许 Web 开发人员控制浏览器允许加载和执行哪些资源来工作。
最严格的 CSP 指令之一是 'unsafe-eval',当省略时,会阻止 JavaScript 通过 eval()、new Function() 以及类似在运行时将字符串编译和执行为代码的构造来执行动态代码。
为什么 CSP 影响 Livewire
默认情况下,Livewire(及其底层的 Alpine.js 框架)使用 new Function() 声明来编译和执行来自 HTML 属性的 JavaScript 表达式,例如:
html
<button wire:click="$set('count', count + 1)">递增</button>
<div wire:show="user.role === 'admin'">管理员面板</div>虽然这种方法比直接使用 eval() 更快更安全,但它仍然违反了许多注重安全的应用程序强制执行的 'unsafe-eval' CSP 指令。
启用 CSP 安全模式
要启用 Livewire 的 CSP 安全模式,您需要修改应用程序的配置:
配置
在您的 config/livewire.php 文件中,将 csp_safe 选项设置为 true:
php
'csp_safe' => true,对 Alpine.js 的影响
重要:当您在 Livewire 中启用 CSP 安全模式时,它也会影响应用程序中的所有 Alpine.js 功能。Alpine 将自动使用其 CSP 安全的求值器,这意味着整个应用程序中的所有 Alpine 表达式都将受到相同的解析限制。
这是大多数开发人员会注意到约束的地方,因为 Alpine 表达式往往比典型的 Livewire 表达式更复杂。
支持的内容
CSP 构建支持您在 Livewire 中使用的大多数常见 JavaScript 表达式:
基本 Livewire 表达式
html
<!-- 这些可以工作 -->
<button wire:click="increment">+</button>
<button wire:click="decrement">-</button>
<button wire:click="reset">重置</button>
<button wire:click="save">保存</button>
<input wire:model="name">
<input wire:model.live="search">带参数的方法调用
html
<!-- 这些可以工作 -->
<button wire:click="updateUser('John', 25)">更新用户</button>
<button wire:click="setCount(42)">设置计数</button>
<button wire:click="saveData({ name: 'John', age: 30 })">保存对象</button>属性访问和更新
html
<!-- 这些可以工作 -->
<input wire:model="user.name">
<input wire:model="settings.theme">
<button wire:click="$set('user.active', true)">激活</button>
<div wire:show="user.role === 'admin'">管理员面板</div>Alpine 中的基本表达式
html
<!-- 这些可以工作 -->
<div x-data="{ count: 0, name: 'Livewire' }" wire:ignore>
<button x-on:click="count++">递增</button>
<span x-text="count"></span>
<span x-text="'Hello ' + name"></span>
<div x-show="count > 5">计数很高!</div>
</div>不支持的内容
一些高级 JavaScript 功能在 CSP 安全模式下不起作用:
复杂 JavaScript 表达式
html
<!-- 这些不起作用 -->
<button wire:click="items.filter(i => i.active).length">计算活动项</button>
<div wire:show="users.some(u => u.role === 'admin')">有管理员</div>
<button wire:click="(() => console.log('Hi'))()">复杂函数</button>模板字面量和高级语法
html
<!-- 这些不起作用 -->
<div x-text="`Hello ${name}`">错误</div>
<div x-data="{ ...defaults }">错误</div>
<button x-on:click="() => doSomething()">错误</button>动态属性访问
html
<!-- 这些不起作用 -->
<div wire:show="user[dynamicProperty]">错误</div>
<button wire:click="this[methodName]()">错误</button>解决限制
对于复杂的 Alpine 表达式,使用 Alpine.data() 或将逻辑移到方法中:
html
<!-- 代替复杂的内联表达式 -->
<div x-data="users">
<div x-show="hasActiveAdmins">管理员面板可用</div>
<span x-text="activeUserCount">0</span>
</div>
<script nonce="[nonce]">
Alpine.data('users', () => ({
users: ...,
get hasActiveAdmins() {
return this.users.filter(u => u.active && u.role === 'admin').length > 0;
},
get activeUserCount() {
return this.users.filter(u => u.active).length;
}
}));
</script>CSP 头部示例
以下是与 Livewire 的 CSP 安全构建配合使用的 CSP 头部示例:
Content-Security-Policy: default-src 'self';
script-src 'nonce-[random]' 'strict-dynamic';
style-src 'self' 'unsafe-inline';关键点:
- 从
script-src指令中移除'unsafe-eval' - 使用
'nonce-[random]'进行基于 nonce 的脚本加载 - 考虑添加
'strict-dynamic'以便更好地兼容动态加载的脚本
性能考虑
CSP 安全构建使用不同的表达式求值器:
- 解析:初始表达式解析略慢(通常可以忽略不计)
- 运行时:简单表达式的运行时性能相似
- 包大小:由于自定义解析器,JavaScript 包略大
对于大多数应用程序,这些差异是察觉不到的,但值得针对您的特定用例进行测试。
测试您的 CSP 实现
要验证您的 CSP 设置是否正常工作:
- 在 Web 服务器或应用程序中启用 CSP 头部
- 在浏览器开发工具中测试 - CSP 违规将出现在控制台中
- 验证表达式正常工作 - 所有 Livewire 和 Alpine 表达式都应正常运行
- 检查控制台错误 - 不应出现
unsafe-eval违规
何时使用 CSP 安全模式
考虑在以下情况下使用 CSP 安全模式:
- 您的应用程序需要严格的 CSP 合规性
- 您正在为安全敏感的环境构建应用程序
- 您的组织安全策略禁止
'unsafe-eval' - 您正在部署到具有强制 CSP 限制的平台