From 8f38a19eae5a9198e44f4088ca275b8a3bebfeec Mon Sep 17 00:00:00 2001 From: Sandor Arpa Date: Thu, 12 Sep 2024 15:54:44 +0100 Subject: [PATCH] PP-13011 add SameSite Lax to cookies Implements `[RFC] SameSite attribute for cookies` add SameSite=Lax to: - session - govuk_pay_cookie_policy - seen_cookie_message - govuk_pay_notifications --- app/assets/js/components/notification-banner.js | 2 +- app/browsered/cookie-functions.js | 7 ++++--- app/utils/cookie.js | 6 ++++-- test/unit/browsered/cookie-banner.test.js | 12 ++++++------ test/unit/browsered/cookie-functions.test.js | 14 ++++++++++++-- 5 files changed, 27 insertions(+), 14 deletions(-) diff --git a/app/assets/js/components/notification-banner.js b/app/assets/js/components/notification-banner.js index ead4c7580d..7266418ff1 100644 --- a/app/assets/js/components/notification-banner.js +++ b/app/assets/js/components/notification-banner.js @@ -7,7 +7,7 @@ e.preventDefault() document.cookie = 'govuk_pay_notifications={"new_contract_terms_banner_dismissed":true}' - + ';max-age=' + SIX_MONTHS_IN_SECS + + ';max-age=' + SIX_MONTHS_IN_SECS + ';SameSite=Lax' runAnalytics() removeBanner() } diff --git a/app/browsered/cookie-functions.js b/app/browsered/cookie-functions.js index 6035c773bf..73053bd3ed 100644 --- a/app/browsered/cookie-functions.js +++ b/app/browsered/cookie-functions.js @@ -1,7 +1,8 @@ 'use strict' const DEFAULT_COOKIE_CONSENT = { - analytics: false + analytics: false, + SameSite: 'Lax' } const COOKIE_CATEGORIES = { @@ -98,7 +99,7 @@ function setConsentCookie (options) { if (Cookie(cookie)) { document.cookie = cookie + '=;expires=' + new Date() + ';domain=' + - getCookieDomain() + ';path=/' + getCookieDomain() + ';path=/' + ';SameSite=Lax' } } } @@ -155,7 +156,7 @@ function setCookie (name, value, options) { if (typeof options === 'undefined') { options = {} } - var cookieString = name + '=' + value + '; path=/; domain=' + getCookieDomain() + var cookieString = name + '=' + value + '; path=/; domain=' + getCookieDomain() + '; SameSite=Lax' if (options.days) { var date = new Date() date.setTime(date.getTime() + (options.days * 24 * 60 * 60 * 1000)) diff --git a/app/utils/cookie.js b/app/utils/cookie.js index 72be679aab..9d0b784c6d 100644 --- a/app/utils/cookie.js +++ b/app/utils/cookie.js @@ -26,7 +26,8 @@ function sessionCookie () { cookie: { ephemeral: false, // when true, cookie expires when the browser closes httpOnly: true, // when true, cookie is not accessible from javascript - secureProxy: !DISABLE_INTERNAL_HTTPS + secureProxy: !DISABLE_INTERNAL_HTTPS, + SameSite: 'Lax' } }) } @@ -41,7 +42,8 @@ function registrationCookie () { cookie: { ephemeral: false, // when true, cookie expires when the browser closes httpOnly: true, // when true, cookie is not accessible from javascript - secureProxy: !DISABLE_INTERNAL_HTTPS // when true, cookie will only be sent over SSL. use key 'secureProxy' instead if you handle SSL not in your node process + secureProxy: !DISABLE_INTERNAL_HTTPS, // when true, cookie will only be sent over SSL. use key 'secureProxy' instead if you handle SSL not in your node process + SameSite: 'Lax' } }) } diff --git a/test/unit/browsered/cookie-banner.test.js b/test/unit/browsered/cookie-banner.test.js index 3223797db2..2ab1e859ae 100644 --- a/test/unit/browsered/cookie-banner.test.js +++ b/test/unit/browsered/cookie-banner.test.js @@ -42,7 +42,7 @@ describe('Cookie banner', () => { analyticsTrackingId = 'test-id' cookieBannerObject.setCookieConsent(true) - expect(document.cookie).equals('govuk_pay_cookie_policy={"analytics":true}') + expect(document.cookie).equals('govuk_pay_cookie_policy={"analytics":true,"SameSite":"Lax"}') expect(document.body.innerHTML).to.contain('You’ve accepted analytics cookies.') expect(analyticsInit.calledOnce).to.be.true @@ -50,7 +50,7 @@ describe('Cookie banner', () => { it('should not initialise analytics if consented and analyticsTrackingId is not configured ', () => { cookieBannerObject.setCookieConsent(true) - expect(document.cookie).equals('govuk_pay_cookie_policy={"analytics":true}') + expect(document.cookie).equals('govuk_pay_cookie_policy={"analytics":true,"SameSite":"Lax"}') expect(document.body.innerHTML).to.contain('You’ve accepted analytics cookies.') expect(analyticsInit.calledOnce).to.be.false }) @@ -58,7 +58,7 @@ describe('Cookie banner', () => { it('should not initialise analytics if not consented ', () => { cookieBannerObject.setCookieConsent(false) - expect(document.cookie).equals('govuk_pay_cookie_policy={"analytics":false}') + expect(document.cookie).equals('govuk_pay_cookie_policy={"analytics":false,"SameSite":"Lax"}') expect(document.body.innerHTML).to.contain('You told us not to use analytics cookies.') expect(analyticsInit.calledOnce).to.be.false @@ -71,7 +71,7 @@ describe('Cookie banner', () => { cookieBannerObject = cookieBanner.initCookieBanner() - expect(document.cookie).equals('govuk_pay_cookie_policy={"analytics":true}') + expect(document.cookie).equals('govuk_pay_cookie_policy={"analytics":true,"SameSite":"Lax"}') expect(cookieBannerObject.$module.style.display).to.be.equal('none') expect(analyticsInit.calledOnce).to.be.true @@ -83,7 +83,7 @@ describe('Cookie banner', () => { cookieBannerObject = cookieBanner.initCookieBanner() - expect(document.cookie).equals('govuk_pay_cookie_policy={"analytics":false}') + expect(document.cookie).equals('govuk_pay_cookie_policy={"analytics":false,"SameSite":"Lax"}') expect(cookieBannerObject.$module.style.display).to.be.equal('none') expect(analyticsInit.notCalled).to.be.true @@ -96,7 +96,7 @@ describe('Cookie banner', () => { cookieBannerObject = cookieBanner.initCookieBanner() - expect(document.cookie).equals('govuk_pay_cookie_policy={"analytics":true}') + expect(document.cookie).equals('govuk_pay_cookie_policy={"analytics":true,"SameSite":"Lax"}') expect(cookieBannerObject.$module.style.display).to.be.equal('none') expect(analyticsInit.notCalled).to.be.true diff --git a/test/unit/browsered/cookie-functions.test.js b/test/unit/browsered/cookie-functions.test.js index 6ddbb5c0b9..d4e8461e42 100644 --- a/test/unit/browsered/cookie-functions.test.js +++ b/test/unit/browsered/cookie-functions.test.js @@ -29,9 +29,10 @@ describe('Cookie functions', () => { }) describe('setCookieConsent', () => { it('should set consent cookie correctly', () => { - cookieFunctions.setConsentCookie({ 'analytics': true }) + cookieFunctions.setConsentCookie({ 'analytics': true, 'SameSite': 'Lax' }) let analyticsCookie = JSON.parse(cookieFunctions.getCookie('govuk_pay_cookie_policy')) expect(analyticsCookie.analytics).to.be.equal(true) + expect(analyticsCookie.SameSite).to.be.equal('Lax') }) it('should update existing analytics and delete analytics cookies if not consented', () => { @@ -39,10 +40,11 @@ describe('Cookie functions', () => { document.cookie = '_ga=ga1;domain=.example.org' document.cookie = '_gid=gid1;domain=.example.org' document.cookie = '_gat_govuk_shared=shared;domain=.example.org' - cookieFunctions.setConsentCookie({ 'analytics': false }) + cookieFunctions.setConsentCookie({ 'analytics': false, 'SameSite': 'Lax' }) let analyticsCookie = JSON.parse(cookieFunctions.getCookie('govuk_pay_cookie_policy')) expect(analyticsCookie.analytics).to.be.equal(false) + expect(analyticsCookie.SameSite).to.be.equal('Lax') expect(cookieFunctions.getCookie('_ga')).to.be.equal(null) expect(cookieFunctions.getCookie('_gid')).to.be.equal(null) expect(cookieFunctions.getCookie('_gat_govuk_shared')).to.be.equal(null) @@ -74,6 +76,14 @@ describe('Cookie functions', () => { expect(expiryDate.getTime()).to.be.greaterThan(previousDateToTargetExpiryDate.getTime()) expect(expiryDate.getTime()).to.be.lessThan(nextDateToTargetExpiryDate.getTime()) }) + + it('should set SameSite on the cookie', () => { + const cookieExpiryDays = 10 + const cookieString = cookieFunctions.setCookie('govuk_pay_cookie_policy', + '{"analytics":false}', { days: cookieExpiryDays }) + + expect(cookieString).to.contain('SameSite=Lax') + }) }) function addDaysToDate (cookieExpiryDays) {