From cbdb2e8de3dad4186ad08902ea4ab2b94ed2ab6e Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Wed, 2 Mar 2022 04:10:25 +0300 Subject: [PATCH 01/11] override default script-src directive to include cloudflare cdn --- src/app/index.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/app/index.ts b/src/app/index.ts index c0bb37d..30e4357 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -54,7 +54,17 @@ const sessionName = EXPRESS_SESSION_NAME; const app = express(); app.use(compression()); // Compress all routes -app.use(helmet()); // protect against well known vulnerabilities +// helps mitigate cross-site scripting attacks and other known vulnerabilities +app.use( + helmet.contentSecurityPolicy({ + // override default script-src directive to include cloudflare cdn + // should consider overriding this to allow individual front-ends set Content-Security-Policy on meta tags themselves if list of exceptions grow + // like so: + directives: { + 'script-src': ["'self'", 'https://cdnjs.cloudflare.com'], + }, + }), +); app.use(morgan('combined', { stream: winstonStream })); // send logs to winston const FileStore = sessionFileStore(session); From b33b0d477c24683f15b10a79cbe5c2746dc69fd4 Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Wed, 2 Mar 2022 04:50:49 +0300 Subject: [PATCH 02/11] Content Security Policy directive to include running inline from approved script sources --- src/app/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/index.ts b/src/app/index.ts index 30e4357..5250fe8 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -61,7 +61,7 @@ app.use( // should consider overriding this to allow individual front-ends set Content-Security-Policy on meta tags themselves if list of exceptions grow // like so: directives: { - 'script-src': ["'self'", 'https://cdnjs.cloudflare.com'], + 'script-src': ["'self'", 'https://cdnjs.cloudflare.com', "'unsafe-inline'"], }, }), ); From 11bbab22d228cb562d9564dfa86dcf5f53d73433 Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Wed, 2 Mar 2022 05:35:38 +0300 Subject: [PATCH 03/11] add exemptions for csp for github --- src/app/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/index.ts b/src/app/index.ts index 5250fe8..d6d35ae 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -57,11 +57,12 @@ app.use(compression()); // Compress all routes // helps mitigate cross-site scripting attacks and other known vulnerabilities app.use( helmet.contentSecurityPolicy({ - // override default script-src directive to include cloudflare cdn + // override default script-src directive to include cloudflare cdn, and github static content // should consider overriding this to allow individual front-ends set Content-Security-Policy on meta tags themselves if list of exceptions grow // like so: directives: { 'script-src': ["'self'", 'https://cdnjs.cloudflare.com', "'unsafe-inline'"], + 'img-src': ["'self'", 'https://github.com', 'https://raw.githubusercontent.com'], }, }), ); From 0da607f195e109879d46c59b07a6cacc8147546d Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Wed, 2 Mar 2022 06:20:31 +0300 Subject: [PATCH 04/11] add img-src to meta csp --- src/app/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/index.ts b/src/app/index.ts index d6d35ae..a37bcaf 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -59,7 +59,7 @@ app.use( helmet.contentSecurityPolicy({ // override default script-src directive to include cloudflare cdn, and github static content // should consider overriding this to allow individual front-ends set Content-Security-Policy on meta tags themselves if list of exceptions grow - // like so: + // like so: directives: { 'script-src': ["'self'", 'https://cdnjs.cloudflare.com', "'unsafe-inline'"], 'img-src': ["'self'", 'https://github.com', 'https://raw.githubusercontent.com'], From 296d8f7f6b0192168d55db577bb77f57d3308dca Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Wed, 2 Mar 2022 06:29:01 +0300 Subject: [PATCH 05/11] disable content security policy - it blocks cdn import of scripts and connection to other endpoints (e.g. keyckloak) --- src/app/index.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/app/index.ts b/src/app/index.ts index a37bcaf..0d450fd 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -56,14 +56,9 @@ const app = express(); app.use(compression()); // Compress all routes // helps mitigate cross-site scripting attacks and other known vulnerabilities app.use( - helmet.contentSecurityPolicy({ - // override default script-src directive to include cloudflare cdn, and github static content - // should consider overriding this to allow individual front-ends set Content-Security-Policy on meta tags themselves if list of exceptions grow - // like so: - directives: { - 'script-src': ["'self'", 'https://cdnjs.cloudflare.com', "'unsafe-inline'"], - 'img-src': ["'self'", 'https://github.com', 'https://raw.githubusercontent.com'], - }, + helmet({ + // disable content security policy - it blocks cdn import of scripts and connection to other endpoints (e.g. keyckloak) + contentSecurityPolicy: false, }), ); app.use(morgan('combined', { stream: winstonStream })); // send logs to winston From 3941443fb02cbdb7ee43279070866270c9cf7642 Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Thu, 3 Mar 2022 04:25:01 +0300 Subject: [PATCH 06/11] add util function to extract url origin from url and it's test --- src/utils/index.ts | 15 +++++++++++++++ src/utils/tests/index.test.ts | 9 +++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/utils/index.ts create mode 100644 src/utils/tests/index.test.ts diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..bd81020 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,15 @@ +/** + * get the url origin from full url + * e.g https://keycloak-example.domain.org from https://keycloak-example.domain.org/auth/realms/example-realm + * @param url + * @returns + */ +export const getOriginFromUrl = (url?: string) => { + if (!url) { + return []; + } + const urlObject = new URL(url); + return [urlObject.origin]; +}; + +export default getOriginFromUrl; diff --git a/src/utils/tests/index.test.ts b/src/utils/tests/index.test.ts new file mode 100644 index 0000000..1678de6 --- /dev/null +++ b/src/utils/tests/index.test.ts @@ -0,0 +1,9 @@ +import { getOriginFromUrl } from '../index'; + +describe('test util functions', () => { + it('get origin from url', () => { + const url = 'https://keycloak-example.domain.org/auth/realms/example-realm'; + const result = getOriginFromUrl(url); + expect(result).toEqual(['https://keycloak-example.domain.org']); + }); +}); From 955c35ca3bdb6fef9c7b1a8c6eaa544df2383dcb Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Thu, 3 Mar 2022 04:27:49 +0300 Subject: [PATCH 07/11] allow csp policy for scripts from cdn, images from github, and connection from keyckloak --- src/app/index.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/app/index.ts b/src/app/index.ts index 0d450fd..f651598 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -36,6 +36,7 @@ import { EXPRESS_SESSION_SECRET, } from '../configs/envs'; import { SESSION_IS_EXPIRED, TOKEN_NOT_FOUND, TOKEN_REFRESH_FAILED } from '../constants'; +import { getOriginFromUrl } from '../utils'; type Dictionary = { [key: string]: unknown }; @@ -57,8 +58,17 @@ app.use(compression()); // Compress all routes // helps mitigate cross-site scripting attacks and other known vulnerabilities app.use( helmet({ - // disable content security policy - it blocks cdn import of scripts and connection to other endpoints (e.g. keyckloak) - contentSecurityPolicy: false, + // override default contentSecurityPolicy directive like script-src to include cloudflare cdn and github static content + // might consider turning this off to allow individual front-ends set Content-Security-Policy on meta tags themselves if list grows long + // + contentSecurityPolicy: { + directives: { + 'script-src': ["'self'", 'https://cdnjs.cloudflare.com', "'unsafe-inline'"], + 'img-src': ["'self'", 'https://github.com', 'https://raw.githubusercontent.com'], + // allow connection from keycloak + 'connect-src': ["'self'", ...getOriginFromUrl(EXPRESS_OPENSRP_AUTHORIZATION_URL)], + }, + }, }), ); app.use(morgan('combined', { stream: winstonStream })); // send logs to winston From 2f33ca8d81b582c00805b5aa3ccbdf4aeff07acd Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Thu, 3 Mar 2022 07:40:29 +0300 Subject: [PATCH 08/11] test unhappy path --- src/utils/tests/index.test.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/utils/tests/index.test.ts b/src/utils/tests/index.test.ts index 1678de6..170a374 100644 --- a/src/utils/tests/index.test.ts +++ b/src/utils/tests/index.test.ts @@ -6,4 +6,11 @@ describe('test util functions', () => { const result = getOriginFromUrl(url); expect(result).toEqual(['https://keycloak-example.domain.org']); }); + it('returns empty array if url is empty or undefined', () => { + const emptyUrl = ''; + const emptyUrlResult = getOriginFromUrl(emptyUrl); + const undefinedUrlResult = getOriginFromUrl(); + expect(emptyUrlResult).toEqual([]); + expect(undefinedUrlResult).toEqual([]); + }); }); From e76882a6a35c07927d6ca82f5252a21e6d9cc393 Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Thu, 3 Mar 2022 07:57:44 +0300 Subject: [PATCH 09/11] add csp dirrective for allowing connection to opensrp server --- src/app/index.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/app/index.ts b/src/app/index.ts index f651598..638490d 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -65,8 +65,12 @@ app.use( directives: { 'script-src': ["'self'", 'https://cdnjs.cloudflare.com', "'unsafe-inline'"], 'img-src': ["'self'", 'https://github.com', 'https://raw.githubusercontent.com'], - // allow connection from keycloak - 'connect-src': ["'self'", ...getOriginFromUrl(EXPRESS_OPENSRP_AUTHORIZATION_URL)], + // allow connection from keycloak and opensrp server + 'connect-src': [ + "'self'", + ...getOriginFromUrl(EXPRESS_OPENSRP_AUTHORIZATION_URL), + ...getOriginFromUrl(EXPRESS_OPENSRP_USER_URL), + ], }, }, }), From 1fb6ca6a97574035fcb0051922ecae9cadc0ff3a Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Fri, 4 Mar 2022 03:20:47 +0300 Subject: [PATCH 10/11] allow all sub domains of githubusercontent --- src/app/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/index.ts b/src/app/index.ts index 638490d..8621af3 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -64,7 +64,7 @@ app.use( contentSecurityPolicy: { directives: { 'script-src': ["'self'", 'https://cdnjs.cloudflare.com', "'unsafe-inline'"], - 'img-src': ["'self'", 'https://github.com', 'https://raw.githubusercontent.com'], + 'img-src': ["'self'", 'https://github.com', 'https://*.githubusercontent.com'], // allow connection from keycloak and opensrp server 'connect-src': [ "'self'", From 29eeb7279a4fcf4a2d15b94c8e26067a95e9368a Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Fri, 4 Mar 2022 04:06:37 +0300 Subject: [PATCH 11/11] fetch cross origin resources without explicit cors request - allow loading images from github --- src/app/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/index.ts b/src/app/index.ts index 8621af3..de8745a 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -73,6 +73,7 @@ app.use( ], }, }, + crossOriginEmbedderPolicy: false, }), ); app.use(morgan('combined', { stream: winstonStream })); // send logs to winston