From b0373ea7b4bb1343bf971cbd446ceac1700a1813 Mon Sep 17 00:00:00 2001 From: Nicolas Faure Date: Wed, 25 Jul 2018 11:22:34 +0200 Subject: [PATCH 1/6] Pass Prebid version to Criteo direct bidder --- modules/criteoBidAdapter.js | 3 ++- test/spec/modules/criteoBidAdapter_spec.js | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index 81da55ebf67..7f5d1b7b280 100755 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -51,7 +51,7 @@ export const spec = { } if (publisherTagAvailable()) { - const adapter = new Criteo.PubTag.Adapters.Prebid(PROFILE_ID, ADAPTER_VERSION, bidRequests, bidderRequest); + const adapter = new Criteo.PubTag.Adapters.Prebid(PROFILE_ID, ADAPTER_VERSION, bidRequests, bidderRequest, '$prebid.version$'); url = adapter.buildCdbUrl(); data = adapter.buildCdbRequest(); } else { @@ -158,6 +158,7 @@ function buildCdbUrl(context) { let url = CDB_ENDPOINT; url += '?profileId=' + PROFILE_ID; url += '&av=' + String(ADAPTER_VERSION); + url += '&wv=' + encodeURIComponent('$prebid.version$'); url += '&cb=' + String(Math.floor(Math.random() * 99999999999)); if (context.integrationMode in INTEGRATION_MODES) { diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js index e855c828b1f..6e2276d7e22 100755 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -73,7 +73,7 @@ describe('The Criteo bidding adapter', () => { }, ]; const request = spec.buildRequests(bidRequests, bidderRequest); - expect(request.url).to.match(/^\/\/bidder\.criteo\.com\/cdb\?profileId=207&av=\d+&cb=\d/); + expect(request.url).to.match(/^\/\/bidder\.criteo\.com\/cdb\?profileId=207&av=\d+&wv=[^&]+&cb=\d/); expect(request.method).to.equal('POST'); const ortbRequest = request.data; expect(ortbRequest.publisher.url).to.equal(utils.getTopWindowUrl()); @@ -113,7 +113,7 @@ describe('The Criteo bidding adapter', () => { }, ]; const request = spec.buildRequests(bidRequests, bidderRequest); - expect(request.url).to.match(/^\/\/bidder\.criteo\.com\/cdb\?profileId=207&av=\d+&cb=\d/); + expect(request.url).to.match(/^\/\/bidder\.criteo\.com\/cdb\?profileId=207&av=\d+&wv=[^&]+&cb=\d/); expect(request.method).to.equal('POST'); const ortbRequest = request.data; expect(ortbRequest.publisher.url).to.equal(utils.getTopWindowUrl()); @@ -152,7 +152,7 @@ describe('The Criteo bidding adapter', () => { }, ]; const request = spec.buildRequests(bidRequests, bidderRequest); - expect(request.url).to.match(/^\/\/bidder\.criteo\.com\/cdb\?profileId=207&av=\d+&cb=\d/); + expect(request.url).to.match(/^\/\/bidder\.criteo\.com\/cdb\?profileId=207&av=\d+&wv=[^&]+&cb=\d/); expect(request.method).to.equal('POST'); const ortbRequest = request.data; expect(ortbRequest.publisher.url).to.equal(utils.getTopWindowUrl()); From 365838b185086ca32ad87f41dcebed908d4e5022 Mon Sep 17 00:00:00 2001 From: Nicolas Faure Date: Tue, 24 Jul 2018 17:31:45 +0200 Subject: [PATCH 2/6] Update Criteo profile IDs --- modules/criteoBidAdapter.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index 7f5d1b7b280..0595fc890f0 100755 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -4,14 +4,15 @@ import { parse } from 'src/url'; import * as utils from 'src/utils'; import find from 'core-js/library/fn/array/find'; -const ADAPTER_VERSION = 8; +const ADAPTER_VERSION = 11; const BIDDER_CODE = 'criteo'; const CDB_ENDPOINT = '//bidder.criteo.com/cdb'; const CRITEO_VENDOR_ID = 91; const INTEGRATION_MODES = { 'amp': 1, }; -const PROFILE_ID = 207; +const PROFILE_ID_INLINE = 207; +const PROFILE_ID_PUBLISHERTAG = 185; // Unminified source code can be found in: https://github.com/Prebid-org/prebid-js-external-js-criteo/blob/master/dist/prod.js const PUBLISHER_TAG_URL = '//static.criteo.net/js/ld/publishertag.prebid.js'; @@ -51,7 +52,7 @@ export const spec = { } if (publisherTagAvailable()) { - const adapter = new Criteo.PubTag.Adapters.Prebid(PROFILE_ID, ADAPTER_VERSION, bidRequests, bidderRequest, '$prebid.version$'); + const adapter = new Criteo.PubTag.Adapters.Prebid(PROFILE_ID_PUBLISHERTAG, ADAPTER_VERSION, bidRequests, bidderRequest, '$prebid.version$'); url = adapter.buildCdbUrl(); data = adapter.buildCdbRequest(); } else { @@ -156,7 +157,7 @@ function buildContext(bidRequests) { */ function buildCdbUrl(context) { let url = CDB_ENDPOINT; - url += '?profileId=' + PROFILE_ID; + url += '?profileId=' + PROFILE_ID_INLINE; url += '&av=' + String(ADAPTER_VERSION); url += '&wv=' + encodeURIComponent('$prebid.version$'); url += '&cb=' + String(Math.floor(Math.random() * 99999999999)); From ccb6f21096723d402416ab2b783ab4dd2fe44bb4 Mon Sep 17 00:00:00 2001 From: Nicolas Faure Date: Mon, 2 Jul 2018 12:50:49 +0200 Subject: [PATCH 3/6] Add RSA verification to Criteo FastBid --- modules/criteoBidAdapter.js | 49 ++++++++++++++++++++-- package.json | 2 + test/spec/modules/criteoBidAdapter_spec.js | 19 ++++++++- 3 files changed, 65 insertions(+), 5 deletions(-) mode change 100644 => 100755 package.json diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index 0595fc890f0..19e6e7fded4 100755 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -3,8 +3,10 @@ import { registerBidder } from 'src/adapters/bidderFactory'; import { parse } from 'src/url'; import * as utils from 'src/utils'; import find from 'core-js/library/fn/array/find'; +import JSEncrypt from 'jsencrypt/bin/jsencrypt'; +import sha256 from 'crypto-js/sha256'; -const ADAPTER_VERSION = 11; +const ADAPTER_VERSION = 13; const BIDDER_CODE = 'criteo'; const CDB_ENDPOINT = '//bidder.criteo.com/cdb'; const CRITEO_VENDOR_ID = 91; @@ -17,6 +19,13 @@ const PROFILE_ID_PUBLISHERTAG = 185; // Unminified source code can be found in: https://github.com/Prebid-org/prebid-js-external-js-criteo/blob/master/dist/prod.js const PUBLISHER_TAG_URL = '//static.criteo.net/js/ld/publishertag.prebid.js'; +export const FAST_BID_PUBKEY = `-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDO1BjAITkFTtP0IMzmF7qsqhpu +y1dGaTPHnjMU9mRZsrnfR3C0sEN5pYEzEcFRPnkJjJuhH8Rnh5+CE+LcKg0Z8ZZ7 +OmOSj0/qnYTAYCu0cR5LiyWG79KlIgUyMbp92ulGg24gAyGrVn4+v/4c53WlOEUp +4YWvb82G0CD5NcDNpQIDAQAB +-----END PUBLIC KEY-----`; + /** @type {BidderSpec} */ export const spec = { code: BIDDER_CODE, @@ -251,6 +260,34 @@ function createNativeAd(id, payload, callback) { `; } +export function cryptoVerify(key, hash, code) { + var jse = new JSEncrypt(); + jse.setPublicKey(key); + return jse.verify(code, hash, sha256); +} + +function validateFastBid(fastBid) { + // The value stored must contain the file's encrypted hash as first line + const firstLineEnd = fastBid.indexOf('\n'); + const firstLine = fastBid.substr(0, firstLineEnd).trim(); + if (firstLine.substr(0, 9) !== '// Hash: ') { + utils.logWarn('No hash found in FastBid'); + return false; + } + + // Remove the hash part from the locally stored value + const fileEncryptedHash = firstLine.substr(9); + const publisherTag = fastBid.substr(firstLineEnd + 1); + + // Verify the hash using cryptography + try { + return cryptoVerify(FAST_BID_PUBKEY, fileEncryptedHash, publisherTag); + } catch (e) { + utils.logWarn('Failed to verify Criteo FastBid'); + return undefined; + } +} + /** * @return {boolean} */ @@ -258,13 +295,17 @@ function tryGetCriteoFastBid() { try { const fastBid = localStorage.getItem('criteo_fast_bid'); if (fastBid !== null) { - eval(fastBid); // eslint-disable-line no-eval - return true; + if (validateFastBid(fastBid) === false) { + utils.logWarn('Invalid Criteo FastBid found'); + localStorage.removeItem('criteo_fast_bid'); + } else { + utils.logInfo('Using Criteo FastBid'); + eval(fastBid); // eslint-disable-line no-eval + } } } catch (e) { // Unable to get fast bid } - return false; } registerBidder(spec); diff --git a/package.json b/package.json old mode 100644 new mode 100755 index 9b476ce1cb3..5e91ca6788d --- a/package.json +++ b/package.json @@ -104,7 +104,9 @@ "dependencies": { "babel-plugin-transform-object-assign": "^6.22.0", "core-js": "^2.4.1", + "crypto-js": "^3.1.9-1", "gulp-sourcemaps": "^2.6.0", + "jsencrypt": "^3.0.0-rc.1", "just-clone": "^1.0.2" } } diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js index 6e2276d7e22..a3c3263199d 100755 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/criteoBidAdapter'; +import { cryptoVerify, spec, FAST_BID_PUBKEY } from 'modules/criteoBidAdapter'; import * as utils from 'src/utils'; describe('The Criteo bidding adapter', () => { @@ -294,4 +294,21 @@ describe('The Criteo bidding adapter', () => { expect(bids[0].height).to.equal(90); }); }); + + describe('cryptoVerify', () => { + const TEST_HASH = 'vBeD8Q7GU6lypFbzB07W8hLGj7NL+p7dI9ro2tCxkrmyv0F6stNuoNd75Us33iNKfEoW+cFWypelr6OJPXxki2MXWatRhJuUJZMcK4VBFnxi3Ro+3a0xEfxE4jJm4eGe98iC898M+/YFHfp+fEPEnS6pEyw124ONIFZFrcejpHU='; + + it('should verify right signature', () => { + expect(cryptoVerify(FAST_BID_PUBKEY, TEST_HASH, 'test')).to.equal(true); + }); + + it('should verify wrong signature', () => { + expect(cryptoVerify(FAST_BID_PUBKEY, TEST_HASH, 'test wrong')).to.equal(false); + }); + + it('should return undefined with incompatible browsers', () => { + // Here use a null hash to make the call to crypto library fail and simulate a browser failure + expect(cryptoVerify(FAST_BID_PUBKEY, null, 'test')).to.equal.undefined; + }); + }); }); From 5d042865caf7296e1a3d5313c90afca4b169750c Mon Sep 17 00:00:00 2001 From: "js.faure" Date: Thu, 20 Sep 2018 12:40:29 +0200 Subject: [PATCH 4/6] Update package-lock with jsencrypt and crypto-js --- package-lock.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/package-lock.json b/package-lock.json index ae24e70fc80..f186d8497f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2826,6 +2826,11 @@ "randomfill": "^1.0.3" } }, + "crypto-js": { + "version": "3.1.9-1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.9-1.tgz", + "integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg=" + }, "css": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/css/-/css-2.2.3.tgz", @@ -8111,6 +8116,11 @@ "dev": true, "optional": true }, + "jsencrypt": { + "version": "3.0.0-rc.1", + "resolved": "https://registry.npmjs.org/jsencrypt/-/jsencrypt-3.0.0-rc.1.tgz", + "integrity": "sha512-gcvGaqerlUJy1Kq6tNgPYteVEoWNemu+9hBe2CdsCIz4rVcwjoTQ72iD1W76/PRMlnkzG0yVh7nwOOMOOUfKmg==" + }, "jsesc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", From ec1af9bcfd4f7eb10c64be4a9d8024892462f024 Mon Sep 17 00:00:00 2001 From: "js.faure" Date: Thu, 20 Sep 2018 12:43:26 +0200 Subject: [PATCH 5/6] Replacing all arrow functions in Mocha function calls --- test/spec/modules/criteoBidAdapter_spec.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js index 9a5c03537fb..d124ebf3709 100755 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -295,18 +295,18 @@ describe('The Criteo bidding adapter', function () { }); }); - describe('cryptoVerify', () => { + describe('cryptoVerify', function () { const TEST_HASH = 'vBeD8Q7GU6lypFbzB07W8hLGj7NL+p7dI9ro2tCxkrmyv0F6stNuoNd75Us33iNKfEoW+cFWypelr6OJPXxki2MXWatRhJuUJZMcK4VBFnxi3Ro+3a0xEfxE4jJm4eGe98iC898M+/YFHfp+fEPEnS6pEyw124ONIFZFrcejpHU='; - it('should verify right signature', () => { + it('should verify right signature', function () { expect(cryptoVerify(FAST_BID_PUBKEY, TEST_HASH, 'test')).to.equal(true); }); - it('should verify wrong signature', () => { + it('should verify wrong signature', function () { expect(cryptoVerify(FAST_BID_PUBKEY, TEST_HASH, 'test wrong')).to.equal(false); }); - it('should return undefined with incompatible browsers', () => { + it('should return undefined with incompatible browsers', function () { // Here use a null hash to make the call to crypto library fail and simulate a browser failure expect(cryptoVerify(FAST_BID_PUBKEY, null, 'test')).to.equal.undefined; }); From e24b1bd4b8b7b6c4df209f1954da5a9539c7e8f6 Mon Sep 17 00:00:00 2001 From: "js.faure" Date: Thu, 20 Sep 2018 12:43:57 +0200 Subject: [PATCH 6/6] Update Adapter Version to 14 --- modules/criteoBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index 19e6e7fded4..284c3f57406 100755 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -6,7 +6,7 @@ import find from 'core-js/library/fn/array/find'; import JSEncrypt from 'jsencrypt/bin/jsencrypt'; import sha256 from 'crypto-js/sha256'; -const ADAPTER_VERSION = 13; +const ADAPTER_VERSION = 14; const BIDDER_CODE = 'criteo'; const CDB_ENDPOINT = '//bidder.criteo.com/cdb'; const CRITEO_VENDOR_ID = 91;