- 48 个 Go 文件所有注释(行注释/块注释/行尾注释,含 _test.go)翻译为中文 - 保留技术标识符:SECURITY_TODO(n)、unsafe-inline、sqlite/mysql、路由参数等 - 代码、字符串字面量、日志消息保持英文原文,零逻辑改动 - go build/vet 通过,go test -count=1 ./... 全绿
40 lines
1.5 KiB
Go
40 lines
1.5 KiB
Go
package middleware
|
|
|
|
import "github.com/gin-gonic/gin"
|
|
|
|
// csp 是 HTML 响应的 Content-Security-Policy 策略。
|
|
//
|
|
// 需要 'unsafe-inline' 是因为模板内嵌了 <script> 与 <style> 块
|
|
// (这些块的 XSS 防御由 Go html/template 提供)。所有第三方资源均已
|
|
// 本地化托管(SECURITY_TODO #9),因此策略不允许其他来源的脚本或样式。
|
|
const csp = "default-src 'self'; " +
|
|
"script-src 'self' 'unsafe-inline'; " +
|
|
"style-src 'self' 'unsafe-inline'; " +
|
|
"img-src 'self' data: https: http:; " +
|
|
"font-src 'self' data: https:; " +
|
|
"connect-src 'self'; " +
|
|
"frame-ancestors 'none'; " +
|
|
"base-uri 'self'; " +
|
|
"form-action 'self'"
|
|
|
|
// SecurityHeaders 为每个响应设置安全加固头:
|
|
// CSP、nosniff、点击劫持防护(X-Frame-Options + frame-ancestors)、
|
|
// Referrer-Policy,以及当请求通过 HTTPS 到达时的 HSTS。
|
|
// 必须在其他中间件之前注册,以确保即使在被拒绝(403/重定向)的响应上
|
|
// 也包含这些头。
|
|
func SecurityHeaders() gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
c.Header("Content-Security-Policy", csp)
|
|
c.Header("X-Content-Type-Options", "nosniff")
|
|
c.Header("X-Frame-Options", "DENY")
|
|
c.Header("Referrer-Policy", "strict-origin-when-cross-origin")
|
|
c.Header("Permissions-Policy", "camera=(), microphone=(), geolocation=()")
|
|
if IsHTTPSRequest(c) {
|
|
// 故意省略 includeSubDomains:站点的某些子域
|
|
// 可能仍通过明文 HTTP 提供访问。
|
|
c.Header("Strict-Transport-Security", "max-age=31536000")
|
|
}
|
|
c.Next()
|
|
}
|
|
}
|