claude code review changes
This commit is contained in:
@@ -56,7 +56,7 @@ type (
|
||||
}
|
||||
|
||||
TransportSecurity struct {
|
||||
// Age in seconts
|
||||
// Age in seconds
|
||||
MaxAge uint
|
||||
IncludeSubDomains bool
|
||||
Preload bool
|
||||
@@ -111,110 +111,126 @@ const (
|
||||
|
||||
// Helmet headers to secure server response
|
||||
func Helmet(opt HelmetOption) func(http.Handler) http.Handler {
|
||||
// Precompute all static header values once at middleware creation time.
|
||||
headers := buildHelmetHeaders(opt)
|
||||
|
||||
return func(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("Content-Security-Policy", opt.ContentSecurityPolicy.value())
|
||||
|
||||
// Opener-Policy
|
||||
if opt.CrossOriginOpenerPolicy == "" {
|
||||
w.Header().Add("Cross-Origin-Opener-Policy", string(OpenerSameOrigin))
|
||||
} else {
|
||||
w.Header().Add("Cross-Origin-Opener-Policy", string(opt.CrossOriginOpenerPolicy))
|
||||
for _, kv := range headers {
|
||||
w.Header().Add(kv.key, kv.value)
|
||||
}
|
||||
|
||||
// Resource-Policy
|
||||
if opt.CrossOriginResourcePolicy == "" {
|
||||
w.Header().Add("Cross-Origin-Resource-Policy", string(ResourceSameOrigin))
|
||||
} else {
|
||||
w.Header().Add("Cross-Origin-Resource-Policy", string(opt.CrossOriginResourcePolicy))
|
||||
}
|
||||
|
||||
// Referrer-Policy
|
||||
rpCount := len(opt.ReferrerPolicy)
|
||||
if rpCount > 0 {
|
||||
refP := make([]string, rpCount)
|
||||
for i, r := range opt.ReferrerPolicy {
|
||||
refP[i] = string(r)
|
||||
}
|
||||
w.Header().Add("Referrer-Policy", string(NoReferrer))
|
||||
} else {
|
||||
// default no referer
|
||||
w.Header().Add("Referrer-Policy", string(NoReferrer))
|
||||
}
|
||||
|
||||
// Origin-Agent-Cluster
|
||||
if opt.OriginAgentCluster {
|
||||
w.Header().Add("Origin-Agent-Cluster", "?1")
|
||||
}
|
||||
|
||||
// Strict-Transport-Security
|
||||
if opt.StrictTransportSecurity != nil {
|
||||
var sb strings.Builder
|
||||
|
||||
if opt.StrictTransportSecurity.MaxAge == 0 {
|
||||
opt.StrictTransportSecurity.MaxAge = YearDuration
|
||||
}
|
||||
|
||||
sb.WriteString(fmt.Sprintf("max-age=%d", opt.StrictTransportSecurity.MaxAge))
|
||||
if opt.StrictTransportSecurity.IncludeSubDomains {
|
||||
sb.WriteString("; includeSubDomains")
|
||||
}
|
||||
|
||||
if opt.StrictTransportSecurity.Preload {
|
||||
sb.WriteString("; preload")
|
||||
}
|
||||
|
||||
w.Header().Add("Strict-Transport-Security", sb.String())
|
||||
}
|
||||
|
||||
if !opt.DisableSniffMimeType {
|
||||
// MIME types advertised in the Content-Current headers should be followed and not be changed
|
||||
w.Header().Add("X-Content-Type-Options", "nosniff")
|
||||
}
|
||||
|
||||
if opt.DisableDNSPrefetch {
|
||||
w.Header().Add("X-DNS-Prefetch-Control", "off")
|
||||
} else {
|
||||
w.Header().Add("X-DNS-Prefetch-Control", "on")
|
||||
}
|
||||
|
||||
if !opt.DisableXDownload {
|
||||
// Instructs Internet Explorer not to open the file directly but to offer it for download first.
|
||||
w.Header().Add("X-Download-Options", "noopen")
|
||||
}
|
||||
|
||||
// indicate whether a browser should be allowed to render a page in iframe | frame | embed | object
|
||||
if opt.XFrameOption == "" {
|
||||
w.Header().Add("X-Frame-Options", string(XFrameSameOrigin))
|
||||
} else {
|
||||
w.Header().Add("X-Frame-Options", string(opt.XFrameOption))
|
||||
}
|
||||
|
||||
if opt.CrossDomainPolicies == "" {
|
||||
w.Header().Add("X-Permitted-Cross-Domain-Policies", string(CDPNone))
|
||||
} else {
|
||||
w.Header().Add("X-Permitted-Cross-Domain-Policies", string(opt.CrossDomainPolicies))
|
||||
}
|
||||
|
||||
w.Header().Del("X-Powered-By")
|
||||
|
||||
if opt.XssProtection {
|
||||
// feature of IE, Chrome and Safari that stops pages from loading when they detect reflected
|
||||
// cross-site scripting (XSS) attacks.
|
||||
w.Header().Add("X-Xss-Protection", "1; mode=block")
|
||||
} else {
|
||||
// Following a decision by Google Chrome developers to disable Auditor,
|
||||
// developers should be able to disable the auditor for older browsers and set it to 0.
|
||||
// The X-XSS-PROTECTION header was found to have a multitude of issues, instead of helping the
|
||||
// developers protect their application.
|
||||
w.Header().Add("X-Xss-Protection", "0")
|
||||
}
|
||||
|
||||
h.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type headerKV struct {
|
||||
key string
|
||||
value string
|
||||
}
|
||||
|
||||
func buildHelmetHeaders(opt HelmetOption) []headerKV {
|
||||
var headers []headerKV
|
||||
|
||||
add := func(key, value string) {
|
||||
headers = append(headers, headerKV{key: key, value: value})
|
||||
}
|
||||
|
||||
// Content-Security-Policy
|
||||
add("Content-Security-Policy", opt.ContentSecurityPolicy.value())
|
||||
|
||||
// Cross-Origin-Opener-Policy
|
||||
if opt.CrossOriginOpenerPolicy == "" {
|
||||
add("Cross-Origin-Opener-Policy", string(OpenerSameOrigin))
|
||||
} else {
|
||||
add("Cross-Origin-Opener-Policy", string(opt.CrossOriginOpenerPolicy))
|
||||
}
|
||||
|
||||
// Cross-Origin-Resource-Policy
|
||||
if opt.CrossOriginResourcePolicy == "" {
|
||||
add("Cross-Origin-Resource-Policy", string(ResourceSameOrigin))
|
||||
} else {
|
||||
add("Cross-Origin-Resource-Policy", string(opt.CrossOriginResourcePolicy))
|
||||
}
|
||||
|
||||
// Referrer-Policy
|
||||
if len(opt.ReferrerPolicy) > 0 {
|
||||
refP := make([]string, len(opt.ReferrerPolicy))
|
||||
for i, r := range opt.ReferrerPolicy {
|
||||
refP[i] = string(r)
|
||||
}
|
||||
add("Referrer-Policy", strings.Join(refP, ","))
|
||||
} else {
|
||||
add("Referrer-Policy", string(NoReferrer))
|
||||
}
|
||||
|
||||
// Origin-Agent-Cluster
|
||||
if opt.OriginAgentCluster {
|
||||
add("Origin-Agent-Cluster", "?1")
|
||||
}
|
||||
|
||||
// Strict-Transport-Security
|
||||
if opt.StrictTransportSecurity != nil {
|
||||
var sb strings.Builder
|
||||
|
||||
maxAge := opt.StrictTransportSecurity.MaxAge
|
||||
if maxAge == 0 {
|
||||
maxAge = YearDuration
|
||||
}
|
||||
|
||||
sb.WriteString(fmt.Sprintf("max-age=%d", maxAge))
|
||||
if opt.StrictTransportSecurity.IncludeSubDomains {
|
||||
sb.WriteString("; includeSubDomains")
|
||||
}
|
||||
if opt.StrictTransportSecurity.Preload {
|
||||
sb.WriteString("; preload")
|
||||
}
|
||||
|
||||
add("Strict-Transport-Security", sb.String())
|
||||
}
|
||||
|
||||
// X-Content-Type-Options
|
||||
if !opt.DisableSniffMimeType {
|
||||
add("X-Content-Type-Options", "nosniff")
|
||||
}
|
||||
|
||||
// X-DNS-Prefetch-Control
|
||||
if opt.DisableDNSPrefetch {
|
||||
add("X-DNS-Prefetch-Control", "off")
|
||||
} else {
|
||||
add("X-DNS-Prefetch-Control", "on")
|
||||
}
|
||||
|
||||
// X-Download-Options
|
||||
if !opt.DisableXDownload {
|
||||
add("X-Download-Options", "noopen")
|
||||
}
|
||||
|
||||
// X-Frame-Options
|
||||
if opt.XFrameOption == "" {
|
||||
add("X-Frame-Options", string(XFrameSameOrigin))
|
||||
} else {
|
||||
add("X-Frame-Options", string(opt.XFrameOption))
|
||||
}
|
||||
|
||||
// X-Permitted-Cross-Domain-Policies
|
||||
if opt.CrossDomainPolicies == "" {
|
||||
add("X-Permitted-Cross-Domain-Policies", string(CDPNone))
|
||||
} else {
|
||||
add("X-Permitted-Cross-Domain-Policies", string(opt.CrossDomainPolicies))
|
||||
}
|
||||
|
||||
// X-Xss-Protection
|
||||
if opt.XssProtection {
|
||||
add("X-Xss-Protection", "1; mode=block")
|
||||
} else {
|
||||
add("X-Xss-Protection", "0")
|
||||
}
|
||||
|
||||
return headers
|
||||
}
|
||||
|
||||
func (csp *CSP) value() string {
|
||||
var sb strings.Builder
|
||||
|
||||
|
||||
Reference in New Issue
Block a user