fix: CSP 策略移除 unsafe-inline,改用 nonce 机制
- SecurityHeaders 中间件生成随机 nonce,注入 context - BuildPageData/BuildAdminPageData 将 CSPNonce 传递给模板 - 所有 19 个模板文件 <script> 标签添加 nonce 属性 - 移除所有内联事件处理(onclick/onerror),改用事件监听 - 移除所有 javascript:void(0) 链接,改用 # 号 + preventDefault - utils.js 添加全局 avatar 图片加载失败回退处理 - common.js 登出按钮添加 preventDefault - audit.js 关闭弹窗按钮改用事件监听
This commit is contained in:
@ -338,18 +338,18 @@
|
||||
{{if eq .ActiveTab "collections"}}
|
||||
<!-- 左侧收藏夹列表 -->
|
||||
<aside class="space-sidebar collection-sidebar">
|
||||
<h2 class="space-sidebar-title collapsible" onclick="toggleFolderSection(this)">
|
||||
<h2 class="space-sidebar-title collapsible" id="folderSectionToggle">
|
||||
我创建的收藏夹
|
||||
<svg class="collapse-arrow" viewBox="0 0 24 24" width="16" height="16"><path fill="currentColor" d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z"/></svg>
|
||||
</h2>
|
||||
<nav class="space-sidebar-nav" id="folder-nav">
|
||||
<a href="javascript:void(0)" class="space-sidebar-link new-folder-btn" onclick="showNewFolderInput()">
|
||||
<a href="#" class="space-sidebar-link new-folder-btn" id="showNewFolderBtn">
|
||||
<svg viewBox="0 0 24 24" width="16" height="16"><path fill="currentColor" d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
|
||||
新建收藏夹
|
||||
</a>
|
||||
<div id="new-folder-input" style="display:none;">
|
||||
<input type="text" id="new-folder-name" placeholder="收藏夹名称" maxlength="50" class="new-folder-input">
|
||||
<button onclick="createFolder()" class="new-folder-submit">确定</button>
|
||||
<button id="createFolderBtn" class="new-folder-submit">确定</button>
|
||||
</div>
|
||||
{{if .FoldersResult}}
|
||||
{{range $f := .FoldersResult.Folders}}
|
||||
@ -576,11 +576,11 @@
|
||||
|
||||
{{template "layout/footer.html" .}}
|
||||
|
||||
<script src="/static/js/common.js?v={{assetV "/static/js/common.js"}}"></script>
|
||||
<script src="/static/js/common.js?v={{assetV "/static/js/common.js"}}" nonce="{{.CSPNonce}}"></script>
|
||||
|
||||
<!-- 访客空间:关注按钮交互 -->
|
||||
{{if and (not .IsOwnSpace) (or (eq .ActiveTab "following") (eq .ActiveTab "followers"))}}
|
||||
<script>
|
||||
<script nonce="{{.CSPNonce}}">
|
||||
(function() {
|
||||
var cards = document.querySelectorAll('.space-user-card');
|
||||
if (!cards.length) return;
|
||||
@ -678,7 +678,7 @@
|
||||
|
||||
<!-- 收藏夹交互脚本 -->
|
||||
{{if eq .ActiveTab "collections"}}
|
||||
<script>
|
||||
<script nonce="{{.CSPNonce}}">
|
||||
function toggleFolderSection(el) {
|
||||
el.parentElement.querySelector('#folder-nav').classList.toggle('collapsed');
|
||||
el.classList.toggle('collapsed');
|
||||
@ -701,6 +701,18 @@ function createFolder() {
|
||||
});
|
||||
}
|
||||
|
||||
// 事件绑定(替代内联 onclick,满足 CSP 无 unsafe-inline)
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var toggle = document.getElementById('folderSectionToggle');
|
||||
if (toggle) toggle.addEventListener('click', function() { toggleFolderSection(this); });
|
||||
|
||||
var showBtn = document.getElementById('showNewFolderBtn');
|
||||
if (showBtn) showBtn.addEventListener('click', function(e) { e.preventDefault(); showNewFolderInput(); });
|
||||
|
||||
var createBtn = document.getElementById('createFolderBtn');
|
||||
if (createBtn) createBtn.addEventListener('click', function() { createFolder(); });
|
||||
});
|
||||
|
||||
// 隐私开关变更保存
|
||||
document.querySelectorAll('.privacy-settings-grid .toggle-switch input').forEach(function(cb) {
|
||||
cb.addEventListener('change', function() {
|
||||
@ -712,7 +724,7 @@ document.querySelectorAll('.privacy-settings-grid .toggle-switch input').forEach
|
||||
|
||||
<!-- 设置页交互脚本 -->
|
||||
{{if eq .ActiveTab "settings"}}
|
||||
<script>
|
||||
<script nonce="{{.CSPNonce}}">
|
||||
// 隐私开关变更时自动保存到后端
|
||||
document.querySelectorAll('#privacy-follow-list, #privacy-follower-list').forEach(function(cb) {
|
||||
cb.addEventListener('change', function() {
|
||||
|
||||
Reference in New Issue
Block a user