Skip to content

Commit c88f919

Browse files
authored
feat: add coep, corp, x-dns-prefetch-control, x-permitted-cross-doman-policies (#102)
* feat: add coep, corp, x-dns-prefetch-control, x-permitted-cross-domain-policies headers * updated readme * update XDNSPrefetchControl to be of type string and fix test * add newly added variables in the default section * remove len check
1 parent 67655e9 commit c88f919

File tree

3 files changed

+133
-20
lines changed

3 files changed

+133
-20
lines changed

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,10 @@ s := secure.New(secure.Options{
8484
FeaturePolicy: "vibrate 'none';", // Deprecated: this header has been renamed to PermissionsPolicy. FeaturePolicy allows the Feature-Policy header with the value to be set with a custom value. Default is "".
8585
PermissionsPolicy: "fullscreen=(), geolocation=()", // PermissionsPolicy allows the Permissions-Policy header with the value to be set with a custom value. Default is "".
8686
CrossOriginOpenerPolicy: "same-origin", // CrossOriginOpenerPolicy allows the Cross-Origin-Opener-Policy header with the value to be set with a custom value. Default is "".
87-
87+
CrossOriginEmbedderPolicy: "require-corp", // CrossOriginEmbedderPolicy allows the Cross-Origin-Embedder-Policy header with the value to be set with a custom value. Default is "".
88+
CrossOriginResourcePolicy: "same-origin", // CrossOriginResourcePolicy allows the Cross-Origin-Resource-Policy header with the value to be set with a custom value. Default is "".
89+
XDNSPrefetchControl: "on", // XDNSPrefetchControl allows the X-DNS-Prefetch-Control header to be set via "on" or "off" keyword. Default is "".
90+
XPermittedCrossDomainPolicies: "none", // XPermittedCrossDomainPolicies allows the X-Permitted-Cross-Domain-Policies to be set with a custom value. Default is "".
8891
IsDevelopment: true, // This will cause the AllowedHosts, SSLRedirect, and STSSeconds/STSIncludeSubdomains options to be ignored during development. When deploying to production, be sure to set this to false.
8992
})
9093
// ...
@@ -121,6 +124,10 @@ l := secure.New(secure.Options{
121124
FeaturePolicy: "",
122125
PermissionsPolicy: "",
123126
CrossOriginOpenerPolicy: "",
127+
CrossOriginEmbedderPolicy: "",
128+
CrossOriginResourcePolicy: "",
129+
XDNSPrefetchControl: "",
130+
XPermittedCrossDomainPolicies: "",
124131
IsDevelopment: false,
125132
})
126133
~~~

secure.go

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,28 @@ import (
1111
type secureCtxKey string
1212

1313
const (
14-
stsHeader = "Strict-Transport-Security"
15-
stsSubdomainString = "; includeSubDomains"
16-
stsPreloadString = "; preload"
17-
frameOptionsHeader = "X-Frame-Options"
18-
frameOptionsValue = "DENY"
19-
contentTypeHeader = "X-Content-Type-Options"
20-
contentTypeValue = "nosniff"
21-
xssProtectionHeader = "X-XSS-Protection"
22-
xssProtectionValue = "1; mode=block"
23-
cspHeader = "Content-Security-Policy"
24-
cspReportOnlyHeader = "Content-Security-Policy-Report-Only"
25-
hpkpHeader = "Public-Key-Pins"
26-
referrerPolicyHeader = "Referrer-Policy"
27-
featurePolicyHeader = "Feature-Policy"
28-
permissionsPolicyHeader = "Permissions-Policy"
29-
coopHeader = "Cross-Origin-Opener-Policy"
30-
31-
ctxDefaultSecureHeaderKey = secureCtxKey("SecureResponseHeader")
32-
cspNonceSize = 16
14+
stsHeader = "Strict-Transport-Security"
15+
stsSubdomainString = "; includeSubDomains"
16+
stsPreloadString = "; preload"
17+
frameOptionsHeader = "X-Frame-Options"
18+
frameOptionsValue = "DENY"
19+
contentTypeHeader = "X-Content-Type-Options"
20+
contentTypeValue = "nosniff"
21+
xssProtectionHeader = "X-XSS-Protection"
22+
xssProtectionValue = "1; mode=block"
23+
cspHeader = "Content-Security-Policy"
24+
cspReportOnlyHeader = "Content-Security-Policy-Report-Only"
25+
hpkpHeader = "Public-Key-Pins"
26+
referrerPolicyHeader = "Referrer-Policy"
27+
featurePolicyHeader = "Feature-Policy"
28+
permissionsPolicyHeader = "Permissions-Policy"
29+
coopHeader = "Cross-Origin-Opener-Policy"
30+
coepHeader = "Cross-Origin-Embedder-Policy"
31+
corpHeader = "Cross-Origin-Resource-Policy"
32+
dnsPreFetchControlHeader = "X-DNS-Prefetch-Control"
33+
permittedCrossDomainPolicies = "X-Permitted-Cross-Domain-Policies"
34+
ctxDefaultSecureHeaderKey = secureCtxKey("SecureResponseHeader")
35+
cspNonceSize = 16
3336
)
3437

3538
// SSLHostFunc is a custom function type that can be used to dynamically set the SSL host of a request.
@@ -91,6 +94,18 @@ type Options struct {
9194
// CrossOriginOpenerPolicy allows you to ensure a top-level document does not share a browsing context group with cross-origin documents. Default is "".
9295
// Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy
9396
CrossOriginOpenerPolicy string
97+
// CrossOriginResourcePolicy header blocks others from loading your resources cross-origin in some cases.
98+
// Reference https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy
99+
CrossOriginResourcePolicy string
100+
// CrossOriginEmbedderPolicy header helps control what resources can be loaded cross-origin.
101+
// Reference https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy
102+
CrossOriginEmbedderPolicy string
103+
// XDNSPrefetchControl header helps control DNS prefetching, which can improve user privacy at the expense of performance.
104+
// Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-DNS-Prefetch-Control
105+
XDNSPrefetchControl string
106+
// XPermittedCrossDomainPolicies header tells some clients (mostly Adobe products) your domain's policy for loading cross-domain content.
107+
// Reference: https://owasp.org/www-project-secure-headers/
108+
XPermittedCrossDomainPolicies string
94109
// SSLHost is the host name that is used to redirect http requests to https. Default is "", which indicates to use the same host.
95110
SSLHost string
96111
// AllowedHosts is a slice of fully qualified domain names that are allowed. Default is an empty slice, which allows any and all host names.
@@ -466,6 +481,29 @@ func (s *Secure) processRequest(w http.ResponseWriter, r *http.Request) (http.He
466481
responseHeader.Set(coopHeader, s.opt.CrossOriginOpenerPolicy)
467482
}
468483

484+
// Cross Origin Resource Policy header.
485+
if len(s.opt.CrossOriginResourcePolicy) > 0 {
486+
responseHeader.Set(corpHeader, s.opt.CrossOriginResourcePolicy)
487+
}
488+
489+
// Cross-Origin-Embedder-Policy header.
490+
if len(s.opt.CrossOriginEmbedderPolicy) > 0 {
491+
responseHeader.Set(coepHeader, s.opt.CrossOriginEmbedderPolicy)
492+
}
493+
494+
// X-DNS-Prefetch-Control header.
495+
switch strings.ToLower(s.opt.XDNSPrefetchControl) {
496+
case "on":
497+
responseHeader.Set(dnsPreFetchControlHeader, "on")
498+
case "off":
499+
responseHeader.Set(dnsPreFetchControlHeader, "off")
500+
}
501+
502+
// X-Permitted-Cross-Domain-Policies header.
503+
if len(s.opt.XPermittedCrossDomainPolicies) > 0 {
504+
responseHeader.Set(permittedCrossDomainPolicies, s.opt.XPermittedCrossDomainPolicies)
505+
}
506+
469507
return responseHeader, r, nil
470508
}
471509

secure_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,74 @@ func TestCrossOriginOpenerPolicy(t *testing.T) {
10461046
expect(t, res.Header().Get("Cross-Origin-Opener-Policy"), "same-origin")
10471047
}
10481048

1049+
func TestCrossOriginEmbedderPolicy(t *testing.T) {
1050+
s := New(Options{
1051+
CrossOriginEmbedderPolicy: "require-corp",
1052+
})
1053+
1054+
res := httptest.NewRecorder()
1055+
req, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/foo", nil)
1056+
1057+
s.Handler(myHandler).ServeHTTP(res, req)
1058+
1059+
expect(t, res.Code, http.StatusOK)
1060+
expect(t, res.Header().Get("Cross-Origin-Embedder-Policy"), "require-corp")
1061+
}
1062+
1063+
func TestCrossOriginResourcePolicy(t *testing.T) {
1064+
s := New(Options{
1065+
CrossOriginResourcePolicy: "same-origin",
1066+
})
1067+
1068+
res := httptest.NewRecorder()
1069+
req, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/foo", nil)
1070+
1071+
s.Handler(myHandler).ServeHTTP(res, req)
1072+
1073+
expect(t, res.Code, http.StatusOK)
1074+
expect(t, res.Header().Get("Cross-Origin-Resource-Policy"), "same-origin")
1075+
}
1076+
1077+
func TestXDNSPreFetchControl(t *testing.T) {
1078+
s := New(Options{
1079+
XDNSPrefetchControl: "on",
1080+
})
1081+
1082+
res := httptest.NewRecorder()
1083+
req, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/foo", nil)
1084+
1085+
s.Handler(myHandler).ServeHTTP(res, req)
1086+
1087+
expect(t, res.Code, http.StatusOK)
1088+
expect(t, res.Header().Get("X-DNS-Prefetch-Control"), "on")
1089+
1090+
k := New(Options{
1091+
XDNSPrefetchControl: "off",
1092+
})
1093+
1094+
res = httptest.NewRecorder()
1095+
req, _ = http.NewRequestWithContext(context.Background(), http.MethodGet, "/bar", nil)
1096+
1097+
k.Handler(myHandler).ServeHTTP(res, req)
1098+
1099+
expect(t, res.Code, http.StatusOK)
1100+
expect(t, res.Header().Get("X-DNS-Prefetch-Control"), "off")
1101+
}
1102+
1103+
func TestXPermittedCrossDomainPolicies(t *testing.T) {
1104+
s := New(Options{
1105+
XPermittedCrossDomainPolicies: "none",
1106+
})
1107+
1108+
res := httptest.NewRecorder()
1109+
req, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/foo", nil)
1110+
1111+
s.Handler(myHandler).ServeHTTP(res, req)
1112+
1113+
expect(t, res.Code, http.StatusOK)
1114+
expect(t, res.Header().Get("X-Permitted-Cross-Domain-Policies"), "none")
1115+
}
1116+
10491117
func TestIsSSL(t *testing.T) {
10501118
s := New(Options{
10511119
SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"},

0 commit comments

Comments
 (0)