Skip to content

Commit

Permalink
Ability to control Referrer-Policy header #2
Browse files Browse the repository at this point in the history
  • Loading branch information
dvershinin committed Dec 5, 2019
1 parent 48a8a7a commit 85c6018
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 16 deletions.
33 changes: 21 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,14 @@ Accept-Ranges: bytes
Connection: keep-alive
X-Frame-Options: SAMEORIGIN <-----------
X-XSS-Protection: 1; mode=block <-----------
Referrer-Policy: no-referrer-when-downgrade <-----------
```

Running `curl -IL http://example.com/some.css` (or `some.js`) will yield additional headers:
Running `curl -IL http://example.com/some.css` (or `some.js`) will yield *additional* security header:

```
HTTP/1.1 200 OK
Server: nginx
Date: Tue, 21 May 2019 16:15:46 GMT
Content-Type: text/css; charset=UTF-8
Vary: Accept-Encoding
Accept-Ranges: bytes
Connection: keep-alive
X-Frame-Options: SAMEORIGIN <-----------
X-XSS-Protection: 1; mode=block <-----------
...
X-Content-Type-Options: nosniff <-----------
```

Expand All @@ -62,6 +56,7 @@ Enables or disables applying security headers. The default set includes:

* `X-Frame-Options: SAMEORIGIN`
* `X-XSS-Protection: 1; mode=block`
* `Referrer-Policy: strict-origin-when-cross-origin`
* `X-Content-Type-Options: nosniff` (for CSS and Javascript)

The values of these headers (or their inclusion) can be controlled with other `security_headers_*` directives below.
Expand All @@ -77,24 +72,38 @@ Enables hiding headers which leak software information:
* `Server`
* `X-Powered-By`

Next are the common security headers being set. It's worth noting that special value of `omit` for directives below
will disable sending a particular header by the module (useful if you want to let your backend app to send it).

### `security_headers_xss`

- **syntax**: `security_headers off | on | block | omit`
- **default**: `block`
- **context**: `http`, `server`, `location`

Controls `X-XSS-Protection` header.
Special `omit` value will disable sending the header.
Special `omit` value will disable sending the header by the module.
The `off` value is for disabling XSS protection: `X-XSS-Protection: 0`.

### `security_headers_frame`

- **syntax**: `security_headers_frames sameorigin | deny | omit`
- **syntax**: `security_headers_frame sameorigin | deny | omit`
- **default**: `sameorigin`
- **context**: `http`, `server`, `location`

Controls inclusion and value of `X-Frame-Options` header.
Special `omit` value will disable sending the header.
Special `omit` value will disable sending the header by the module.


### `security_headers_referrer_policy`

- **syntax**: `security_headers_referrer_policy no-referrer | no-referrer-when-downgrade | same-origin | origin
| strict-origin | origin-when-cross-origin | strict-origin-when-cross-origin | unsafe-url | omit`
- **default**: `no-referrer-when-downgrade`
- **context**: `http`, `server`, `location`

Controls inclusion and value of [`Referrer-Policy`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy) header.
Special `omit` value will disable sending the header by the module.

### `security_headers_nosniff_types`

Expand Down
74 changes: 71 additions & 3 deletions src/ngx_http_security_headers_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,25 @@
#define NGX_HTTP_FO_HEADER_SAME 1
#define NGX_HTTP_FO_HEADER_DENY 2

/* The Referrer Policy header */
#define NGX_HTTP_RP_HEADER_NO 1
#define NGX_HTTP_RP_HEADER_DOWNGRADE 2
#define NGX_HTTP_RP_HEADER_SAME_ORIGIN 3
#define NGX_HTTP_RP_HEADER_ORIGIN 4
#define NGX_HTTP_RP_HEADER_STRICT_ORIGIN 5
#define NGX_HTTP_RP_HEADER_ORIGIN_WHEN_CROSS 6
#define NGX_HTTP_RP_HEADER_STRICT_ORIG_WHEN_CROSS 7
#define NGX_HTTP_RP_HEADER_UNSAFE_URL 8



typedef struct {
ngx_flag_t enable;
ngx_flag_t hide_server_tokens;

ngx_uint_t xss;
ngx_uint_t fo;
ngx_uint_t rp;

ngx_hash_t nosniff_types;
ngx_array_t *types_keys;
Expand All @@ -44,6 +56,34 @@ static ngx_conf_enum_t ngx_http_frame_options[] = {
{ ngx_null_string, 0 }
};

static ngx_conf_enum_t ngx_http_referrer_policy[] = {
{ ngx_string("no-referrer"),
NGX_HTTP_RP_HEADER_NO },

{ ngx_string("no-referrer-when-downgrade"),
NGX_HTTP_RP_HEADER_DOWNGRADE },

{ ngx_string("same-origin"),
NGX_HTTP_RP_HEADER_SAME_ORIGIN },

{ ngx_string("origin"),
NGX_HTTP_RP_HEADER_ORIGIN },

{ ngx_string("strict-origin"),
NGX_HTTP_RP_HEADER_STRICT_ORIGIN },

{ ngx_string("origin-when-cross-origin"),
NGX_HTTP_RP_HEADER_ORIGIN_WHEN_CROSS },

{ ngx_string("unsafe-url"),
NGX_HTTP_RP_HEADER_UNSAFE_URL },

{ ngx_string("omit"),
NGX_HTTP_SECURITY_HEADER_OMIT },

{ ngx_null_string, 0 }
};

static ngx_int_t ngx_http_security_headers_filter(ngx_http_request_t *r);
static void *ngx_http_security_headers_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_security_headers_merge_loc_conf(ngx_conf_t *cf,
Expand Down Expand Up @@ -96,6 +136,13 @@ static ngx_command_t ngx_http_security_headers_commands[] = {
offsetof(ngx_http_security_headers_loc_conf_t, fo),
ngx_http_frame_options },

{ ngx_string("security_headers_referrer_policy"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_enum_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_security_headers_loc_conf_t, rp),
ngx_http_referrer_policy },

ngx_null_command
};

Expand Down Expand Up @@ -220,9 +267,27 @@ ngx_http_security_headers_filter(ngx_http_request_t *r)
}

/* Referrer-Policy: no-referrer-when-downgrade */
if (r->headers_out.status != NGX_HTTP_NOT_MODIFIED) {
ngx_str_set(&key, "Referrer-Policy");
ngx_str_set(&val, "no-referrer-when-downgrade");
if (r->headers_out.status != NGX_HTTP_NOT_MODIFIED
&& NGX_HTTP_SECURITY_HEADER_OMIT != slcf->rp) {
ngx_str_set(&key, "Referrer-Policy");

if (NGX_HTTP_RP_HEADER_NO == slcf->rp) {
ngx_str_set(&val, "no-referrer");
} else if (NGX_HTTP_RP_HEADER_DOWNGRADE == slcf->rp) {
ngx_str_set(&val, "no-referrer-when-downgrade");
} else if (NGX_HTTP_RP_HEADER_SAME_ORIGIN == slcf->rp) {
ngx_str_set(&val, "same-origin");
} else if (NGX_HTTP_RP_HEADER_ORIGIN == slcf->rp) {
ngx_str_set(&val, "origin");
} else if (NGX_HTTP_RP_HEADER_STRICT_ORIGIN == slcf->rp) {
ngx_str_set(&val, "strict-origin");
} else if (NGX_HTTP_RP_HEADER_ORIGIN_WHEN_CROSS == slcf->rp) {
ngx_str_set(&val, "origin-when-cross-origin");
} else if (NGX_HTTP_RP_HEADER_STRICT_ORIG_WHEN_CROSS == slcf->rp) {
ngx_str_set(&val, "strict-origin-when-cross-origin");
} else if (NGX_HTTP_RP_HEADER_UNSAFE_URL == slcf->rp) {
ngx_str_set(&val, "unsafe-url");
}
ngx_set_headers_out_by_search(r, &key, &val);
}

Expand All @@ -245,6 +310,7 @@ ngx_http_security_headers_create_loc_conf(ngx_conf_t *cf)

conf->xss = NGX_CONF_UNSET_UINT;
conf->fo = NGX_CONF_UNSET_UINT;
conf->rp = NGX_CONF_UNSET_UINT;
conf->enable = NGX_CONF_UNSET;
conf->hide_server_tokens = NGX_CONF_UNSET_UINT;

Expand Down Expand Up @@ -275,6 +341,8 @@ ngx_http_security_headers_merge_loc_conf(ngx_conf_t *cf, void *parent,
NGX_HTTP_XSS_HEADER_BLOCK);
ngx_conf_merge_uint_value(conf->fo, prev->fo,
NGX_HTTP_FO_HEADER_SAME);
ngx_conf_merge_uint_value(conf->rp, prev->rp,
NGX_HTTP_RP_HEADER_STRICT_ORIG_WHEN_CROSS);

return NGX_CONF_OK;
}
Expand Down
46 changes: 45 additions & 1 deletion t/headers.t
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,48 @@ hello world
!x-content-type-options
x-frame-options: SAMEORIGIN
!Server
Referrer-Policy: no-referrer-when-downgrade
Referrer-Policy: strict-origin-when-cross-origin
=== TEST 6: custom referrer-policy
--- config
security_headers on;
security_headers_referrer_policy unsafe-url;
location = /hello {
return 200 "hello world\n";
}
--- request
GET /hello
--- response_body
hello world
--- response_headers
!x-content-type-options
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
referrer-policy: unsafe-url
=== TEST 7: co-exist with add header for custom referrer-policy
--- config
security_headers on;
security_headers_referrer_policy omit;
location = /hello {
return 200 "hello world\n";
add_header 'Referrer-Policy' 'origin';
}
location = /hello-proxied {
proxy_buffering off;
proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/hello;
}
--- request
GET /hello-proxied
--- response_body
hello world
--- response_headers
!x-content-type-options
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
referrer-policy: origin

0 comments on commit 85c6018

Please sign in to comment.