diff --git a/internal/common/helper.go b/internal/common/helper.go
index 7ba88d1..3caa040 100644
--- a/internal/common/helper.go
+++ b/internal/common/helper.go
@@ -82,6 +82,10 @@ func BuildPageData(c *gin.Context, extra gin.H) gin.H {
for k, v := range extra {
data[k] = v
}
+ // 注入 CSP nonce(由 SecurityHeaders 中间件生成)
+ if nonce, exists := c.Get("csp_nonce"); exists {
+ data["CSPNonce"] = nonce
+ }
if username, exists := c.Get("username"); exists {
data["IsLoggedIn"] = true
data["Username"] = username
diff --git a/internal/middleware/security.go b/internal/middleware/security.go
index 7698c6e..cab764d 100644
--- a/internal/middleware/security.go
+++ b/internal/middleware/security.go
@@ -1,20 +1,37 @@
package middleware
import (
+ "crypto/rand"
+ "encoding/base64"
+
"github.com/gin-gonic/gin"
)
+// generateNonce 生成 16 字节随机 nonce(base64 编码)
+func generateNonce() string {
+ b := make([]byte, 16)
+ if _, err := rand.Read(b); err != nil {
+ // 降级:使用固定长度回退(极度罕见,仅 /dev/urandom 故障时)
+ panic("failed to generate CSP nonce: " + err.Error())
+ }
+ return base64.StdEncoding.EncodeToString(b)
+}
+
// SecurityHeaders 添加安全相关 HTTP 响应头
// 作为纵深防御,不影响业务逻辑,纯附加
func SecurityHeaders() gin.HandlerFunc {
return func(c *gin.Context) {
+ // 生成一次性 nonce,用于 CSP 策略和模板内
-
+
+