Skip to content

Commit 5950c75

Browse files
Copilotdvershinin
andcommitted
Add support for Cross-Origin headers (COOP, CORP, COEP)
Co-authored-by: dvershinin <250071+dvershinin@users.noreply.github.com>
1 parent c518ac1 commit 5950c75

File tree

3 files changed

+388
-1
lines changed

3 files changed

+388
-1
lines changed

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,36 @@ Special `omit` value will disable sending the header by the module.
135135
Controls inclusion and value of [`Referrer-Policy`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy) header.
136136
Special `omit` value will disable sending the header by the module.
137137

138+
### `security_headers_coop`
139+
140+
- **syntax**: `security_headers_coop unsafe-none | same-origin-allow-popups | same-origin | omit`
141+
- **default**: `omit`
142+
- **context**: `http`, `server`, `location`
143+
144+
Controls inclusion and value of [`Cross-Origin-Opener-Policy`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy) header.
145+
This header allows you to ensure a top-level document does not share a browsing context group with cross-origin documents.
146+
Special `omit` value (default) will disable sending the header by the module.
147+
148+
### `security_headers_corp`
149+
150+
- **syntax**: `security_headers_corp same-site | same-origin | cross-origin | omit`
151+
- **default**: `omit`
152+
- **context**: `http`, `server`, `location`
153+
154+
Controls inclusion and value of [`Cross-Origin-Resource-Policy`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy) header.
155+
This header conveys a desire that the browser blocks no-cors cross-origin/cross-site requests to the given resource.
156+
Special `omit` value (default) will disable sending the header by the module.
157+
158+
### `security_headers_coep`
159+
160+
- **syntax**: `security_headers_coep unsafe-none | require-corp | omit`
161+
- **default**: `omit`
162+
- **context**: `http`, `server`, `location`
163+
164+
Controls inclusion and value of [`Cross-Origin-Embedder-Policy`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy) header.
165+
This header prevents a document from loading any cross-origin resources that don't explicitly grant the document permission.
166+
Special `omit` value (default) will disable sending the header by the module.
167+
138168
## Install
139169

140170
We highly recommend installing using packages, where available,

src/ngx_http_security_headers_module.c

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,20 @@
2727
#define NGX_HTTP_RP_HEADER_STRICT_ORIG_WHEN_CROSS 7
2828
#define NGX_HTTP_RP_HEADER_UNSAFE_URL 8
2929

30+
/* Cross-Origin-Opener-Policy header */
31+
#define NGX_HTTP_COOP_HEADER_UNSAFE_NONE 1
32+
#define NGX_HTTP_COOP_HEADER_SAME_ORIGIN_POPUPS 2
33+
#define NGX_HTTP_COOP_HEADER_SAME_ORIGIN 3
34+
35+
/* Cross-Origin-Resource-Policy header */
36+
#define NGX_HTTP_CORP_HEADER_SAME_SITE 1
37+
#define NGX_HTTP_CORP_HEADER_SAME_ORIGIN 2
38+
#define NGX_HTTP_CORP_HEADER_CROSS_ORIGIN 3
39+
40+
/* Cross-Origin-Embedder-Policy header */
41+
#define NGX_HTTP_COEP_HEADER_UNSAFE_NONE 1
42+
#define NGX_HTTP_COEP_HEADER_REQUIRE_CORP 2
43+
3044
typedef struct {
3145
ngx_flag_t enable;
3246
ngx_flag_t hide_server_tokens;
@@ -35,6 +49,9 @@ typedef struct {
3549
ngx_uint_t xss;
3650
ngx_uint_t fo;
3751
ngx_uint_t rp;
52+
ngx_uint_t coop;
53+
ngx_uint_t corp;
54+
ngx_uint_t coep;
3855

3956
ngx_hash_t text_types;
4057
ngx_array_t *text_types_keys;
@@ -113,6 +130,51 @@ static ngx_conf_enum_t ngx_http_referrer_policy[] = {
113130
{ ngx_null_string, 0 }
114131
};
115132

133+
static ngx_conf_enum_t ngx_http_cross_origin_opener_policy[] = {
134+
{ ngx_string("unsafe-none"),
135+
NGX_HTTP_COOP_HEADER_UNSAFE_NONE },
136+
137+
{ ngx_string("same-origin-allow-popups"),
138+
NGX_HTTP_COOP_HEADER_SAME_ORIGIN_POPUPS },
139+
140+
{ ngx_string("same-origin"),
141+
NGX_HTTP_COOP_HEADER_SAME_ORIGIN },
142+
143+
{ ngx_string("omit"),
144+
NGX_HTTP_SECURITY_HEADER_OMIT },
145+
146+
{ ngx_null_string, 0 }
147+
};
148+
149+
static ngx_conf_enum_t ngx_http_cross_origin_resource_policy[] = {
150+
{ ngx_string("same-site"),
151+
NGX_HTTP_CORP_HEADER_SAME_SITE },
152+
153+
{ ngx_string("same-origin"),
154+
NGX_HTTP_CORP_HEADER_SAME_ORIGIN },
155+
156+
{ ngx_string("cross-origin"),
157+
NGX_HTTP_CORP_HEADER_CROSS_ORIGIN },
158+
159+
{ ngx_string("omit"),
160+
NGX_HTTP_SECURITY_HEADER_OMIT },
161+
162+
{ ngx_null_string, 0 }
163+
};
164+
165+
static ngx_conf_enum_t ngx_http_cross_origin_embedder_policy[] = {
166+
{ ngx_string("unsafe-none"),
167+
NGX_HTTP_COEP_HEADER_UNSAFE_NONE },
168+
169+
{ ngx_string("require-corp"),
170+
NGX_HTTP_COEP_HEADER_REQUIRE_CORP },
171+
172+
{ ngx_string("omit"),
173+
NGX_HTTP_SECURITY_HEADER_OMIT },
174+
175+
{ ngx_null_string, 0 }
176+
};
177+
116178
static ngx_int_t ngx_http_security_headers_filter(ngx_http_request_t *r);
117179
static void *ngx_http_security_headers_create_loc_conf(ngx_conf_t *cf);
118180
static char *ngx_http_security_headers_merge_loc_conf(ngx_conf_t *cf,
@@ -173,6 +235,27 @@ static ngx_command_t ngx_http_security_headers_commands[] = {
173235
offsetof(ngx_http_security_headers_loc_conf_t, rp),
174236
ngx_http_referrer_policy },
175237

238+
{ ngx_string("security_headers_coop"),
239+
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
240+
ngx_conf_set_enum_slot,
241+
NGX_HTTP_LOC_CONF_OFFSET,
242+
offsetof(ngx_http_security_headers_loc_conf_t, coop),
243+
ngx_http_cross_origin_opener_policy },
244+
245+
{ ngx_string("security_headers_corp"),
246+
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
247+
ngx_conf_set_enum_slot,
248+
NGX_HTTP_LOC_CONF_OFFSET,
249+
offsetof(ngx_http_security_headers_loc_conf_t, corp),
250+
ngx_http_cross_origin_resource_policy },
251+
252+
{ ngx_string("security_headers_coep"),
253+
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
254+
ngx_conf_set_enum_slot,
255+
NGX_HTTP_LOC_CONF_OFFSET,
256+
offsetof(ngx_http_security_headers_loc_conf_t, coep),
257+
ngx_http_cross_origin_embedder_policy },
258+
176259
{ ngx_string("security_headers_text_types"),
177260
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
178261
ngx_http_types_slot,
@@ -372,6 +455,75 @@ ngx_http_security_headers_filter(ngx_http_request_t *r)
372455
}
373456
}
374457

458+
/* Cross-Origin-Opener-Policy */
459+
if (r->headers_out.status != NGX_HTTP_NOT_MODIFIED
460+
&& NGX_HTTP_SECURITY_HEADER_OMIT != slcf->coop) {
461+
462+
switch (slcf->coop) {
463+
case NGX_HTTP_COOP_HEADER_UNSAFE_NONE:
464+
ngx_str_set(&val, "unsafe-none");
465+
break;
466+
case NGX_HTTP_COOP_HEADER_SAME_ORIGIN_POPUPS:
467+
ngx_str_set(&val, "same-origin-allow-popups");
468+
break;
469+
case NGX_HTTP_COOP_HEADER_SAME_ORIGIN:
470+
ngx_str_set(&val, "same-origin");
471+
break;
472+
default:
473+
val.len = 0;
474+
val.data = NULL;
475+
}
476+
if (val.data) {
477+
ngx_str_set(&key, "Cross-Origin-Opener-Policy");
478+
ngx_set_headers_out_by_search(r, &key, &val);
479+
}
480+
}
481+
482+
/* Cross-Origin-Resource-Policy */
483+
if (r->headers_out.status != NGX_HTTP_NOT_MODIFIED
484+
&& NGX_HTTP_SECURITY_HEADER_OMIT != slcf->corp) {
485+
486+
switch (slcf->corp) {
487+
case NGX_HTTP_CORP_HEADER_SAME_SITE:
488+
ngx_str_set(&val, "same-site");
489+
break;
490+
case NGX_HTTP_CORP_HEADER_SAME_ORIGIN:
491+
ngx_str_set(&val, "same-origin");
492+
break;
493+
case NGX_HTTP_CORP_HEADER_CROSS_ORIGIN:
494+
ngx_str_set(&val, "cross-origin");
495+
break;
496+
default:
497+
val.len = 0;
498+
val.data = NULL;
499+
}
500+
if (val.data) {
501+
ngx_str_set(&key, "Cross-Origin-Resource-Policy");
502+
ngx_set_headers_out_by_search(r, &key, &val);
503+
}
504+
}
505+
506+
/* Cross-Origin-Embedder-Policy */
507+
if (r->headers_out.status != NGX_HTTP_NOT_MODIFIED
508+
&& NGX_HTTP_SECURITY_HEADER_OMIT != slcf->coep) {
509+
510+
switch (slcf->coep) {
511+
case NGX_HTTP_COEP_HEADER_UNSAFE_NONE:
512+
ngx_str_set(&val, "unsafe-none");
513+
break;
514+
case NGX_HTTP_COEP_HEADER_REQUIRE_CORP:
515+
ngx_str_set(&val, "require-corp");
516+
break;
517+
default:
518+
val.len = 0;
519+
val.data = NULL;
520+
}
521+
if (val.data) {
522+
ngx_str_set(&key, "Cross-Origin-Embedder-Policy");
523+
ngx_set_headers_out_by_search(r, &key, &val);
524+
}
525+
}
526+
375527

376528

377529
/* proceed to the next handler in chain */
@@ -392,6 +544,9 @@ ngx_http_security_headers_create_loc_conf(ngx_conf_t *cf)
392544
conf->xss = NGX_CONF_UNSET_UINT;
393545
conf->fo = NGX_CONF_UNSET_UINT;
394546
conf->rp = NGX_CONF_UNSET_UINT;
547+
conf->coop = NGX_CONF_UNSET_UINT;
548+
conf->corp = NGX_CONF_UNSET_UINT;
549+
conf->coep = NGX_CONF_UNSET_UINT;
395550
conf->enable = NGX_CONF_UNSET;
396551
conf->hide_server_tokens = NGX_CONF_UNSET_UINT;
397552
conf->hsts_preload = NGX_CONF_UNSET_UINT;
@@ -425,6 +580,12 @@ ngx_http_security_headers_merge_loc_conf(ngx_conf_t *cf, void *parent,
425580
NGX_HTTP_FO_HEADER_SAME);
426581
ngx_conf_merge_uint_value(conf->rp, prev->rp,
427582
NGX_HTTP_RP_HEADER_STRICT_ORIG_WHEN_CROSS);
583+
ngx_conf_merge_uint_value(conf->coop, prev->coop,
584+
NGX_HTTP_SECURITY_HEADER_OMIT);
585+
ngx_conf_merge_uint_value(conf->corp, prev->corp,
586+
NGX_HTTP_SECURITY_HEADER_OMIT);
587+
ngx_conf_merge_uint_value(conf->coep, prev->coep,
588+
NGX_HTTP_SECURITY_HEADER_OMIT);
428589

429590
return NGX_CONF_OK;
430591
}

0 commit comments

Comments
 (0)