Skip to content

Commit

Permalink
Update XSS security header default to disabled (#4352)
Browse files Browse the repository at this point in the history
  • Loading branch information
devinivy authored May 1, 2022
1 parent de4b992 commit df42a0c
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 12 deletions.
18 changes: 11 additions & 7 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -3345,13 +3345,17 @@ following options:
otherwise this field is ignored. If `rule` is `'allow-from'` but `source` is unset, the
rule will be automatically changed to `'sameorigin'`.

- `xss` - boolean that controls the 'X-XSS-PROTECTION' header for Internet Explorer. Defaults to
`true` which sets the header to equal `'1; mode=block'`.
- Note: this setting can create a security vulnerability in versions of Internet Exploere below
8, as well as unpatched versions of IE8. See [here](https://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities/)
and [here](https://technet.microsoft.com/library/security/ms10-002) for more information. If
you actively support old versions of IE, it may be wise to explicitly set this flag to
`false`.
- `xss` - controls the 'X-XSS-Protection' header, where:

- `'disable'` - the header will be set to `'0'`. This is the default value.
- `'enable'` - the header will be set to `'1; mode=block'`.
- `false` - the header will be omitted.

Note: when enabled, this setting can create a security vulnerabilities in versions of Internet Explorer
below 8, unpatched versions of IE8, and browsers that employ an XSS filter/auditor. See
[here](https://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities/),
[here](https://technet.microsoft.com/library/security/ms10-002), and
[here](https://blog.innerht.ml/the-misunderstood-x-xss-protection/) for more information.

- `noOpen` - boolean controlling the 'X-Download-Options' header for Internet Explorer, preventing
downloads from executing in your context. Defaults to `true` setting the header to `'noopen'`.
Expand Down
2 changes: 1 addition & 1 deletion lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ internals.routeBase = Validate.object({
})
])
.default('deny'),
xss: Validate.boolean().default(true),
xss: Validate.valid('enabled', 'disabled', false).default('disabled'),
noOpen: Validate.boolean().default(true),
noSniff: Validate.boolean().default(true),
referrer: Validate.alternatives([
Expand Down
5 changes: 4 additions & 1 deletion lib/security.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,12 @@ exports.headers = function (response) {
response._header('x-frame-options', security._xframe, { override: false });
}

if (security.xss) {
if (security.xss === 'enabled') {
response._header('x-xss-protection', '1; mode=block', { override: false });
}
else if (security.xss === 'disabled') {
response._header('x-xss-protection', '0', { override: false });
}

if (security.noOpen) {
response._header('x-download-options', 'noopen', { override: false });
Expand Down
36 changes: 33 additions & 3 deletions test/headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ describe('Headers', () => {
expect(res.result).to.equal('Test');
expect(res.headers['strict-transport-security']).to.equal('max-age=15768000');
expect(res.headers['x-frame-options']).to.equal('DENY');
expect(res.headers['x-xss-protection']).to.equal('1; mode=block');
expect(res.headers['x-xss-protection']).to.equal('0');
expect(res.headers['x-download-options']).to.equal('noopen');
expect(res.headers['x-content-type-options']).to.equal('nosniff');
});
Expand Down Expand Up @@ -243,7 +243,7 @@ describe('Headers', () => {
expect(res.result).to.equal('Test');
expect(res.headers['strict-transport-security']).to.not.exist();
expect(res.headers['x-frame-options']).to.equal('DENY');
expect(res.headers['x-xss-protection']).to.equal('1; mode=block');
expect(res.headers['x-xss-protection']).to.equal('0');
expect(res.headers['x-download-options']).to.equal('noopen');
expect(res.headers['x-content-type-options']).to.equal('nosniff');
});
Expand Down Expand Up @@ -335,7 +335,7 @@ describe('Headers', () => {
expect(res.result).to.equal('Test');
expect(res.headers['x-frame-options']).to.not.exist();
expect(res.headers['strict-transport-security']).to.equal('max-age=15768000');
expect(res.headers['x-xss-protection']).to.equal('1; mode=block');
expect(res.headers['x-xss-protection']).to.equal('0');
expect(res.headers['x-download-options']).to.equal('noopen');
expect(res.headers['x-content-type-options']).to.equal('nosniff');
});
Expand Down Expand Up @@ -418,6 +418,36 @@ describe('Headers', () => {
expect(res.headers['x-content-type-options']).to.not.exist();
});

it('sets the x-xss-protection header when security.xss is enabled', async () => {

const server = Hapi.server({ routes: { security: { xss: 'enabled' } } });
server.route({ method: 'GET', path: '/', handler: () => 'Test' });

const res = await server.inject({ url: '/' });
expect(res.result).to.exist();
expect(res.result).to.equal('Test');
expect(res.headers['x-xss-protection']).to.equal('1; mode=block');
expect(res.headers['strict-transport-security']).to.equal('max-age=15768000');
expect(res.headers['x-frame-options']).to.equal('DENY');
expect(res.headers['x-download-options']).to.equal('noopen');
expect(res.headers['x-content-type-options']).to.equal('nosniff');
});

it('sets the x-xss-protection header when security.xss is disabled', async () => {

const server = Hapi.server({ routes: { security: { xss: 'disabled' } } });
server.route({ method: 'GET', path: '/', handler: () => 'Test' });

const res = await server.inject({ url: '/' });
expect(res.result).to.exist();
expect(res.result).to.equal('Test');
expect(res.headers['x-xss-protection']).to.equal('0');
expect(res.headers['strict-transport-security']).to.equal('max-age=15768000');
expect(res.headers['x-frame-options']).to.equal('DENY');
expect(res.headers['x-download-options']).to.equal('noopen');
expect(res.headers['x-content-type-options']).to.equal('nosniff');
});

it('does not set the x-xss-protection header when security.xss is false', async () => {

const server = Hapi.server({ routes: { security: { xss: false } } });
Expand Down

0 comments on commit df42a0c

Please sign in to comment.