Pharming je zpět a silnější

23. 3. 2007
Doba čtení: 7 minut

Sdílet

Autor: 29
Když se klienti České spořitelny stali před nedávnem terčem útoku internetového podvodníka, vrátil se do tuzemska po nějaké době fenomén zvaný pharming. Co je tato metoda internetového zločinu zač a jak se jí vyhnout? Představuje pharming skutečné nebezpečí?

Ještě relativně nedávno jsme mohli konstatovat, že útoky směřované proti uživatelům webových služeb v Česku nejsou tak velikým nebezpečím jako v zahraničí. Důvodů bylo více. Útoky, jejichž součástí jsou podvodné e-maily, byly směřovány proti globálním webovým službám, jako je například PayPal. Tyto služby ale v ČR nefungovaly, nebo je čeští uživatelé mohli využívat jen v omezené míře. Podvodné e-maily přicházely v angličtině, což podstatně omezovalo jejich úspěšnost. Lidé, kteří by na útok zareagovali, vesměs neumí anglicky, zatímco ti gramotnější bývají také zběhlejší v oblasti informační bezpečnosti a žádné své citlivé údaje cizím lidem nepošlou.

S tímto falešným pocitem bezpečí je podle všeho definitivní konec. Pro elektronické (tím mám na mysli v elektronickém světě působící) zločince jsme se definitivně stali vhodnou a vyhledávanou klientelou. V poslední době došlo k několika útokům zaměřeným na zákazníky bank. Obětí zatím posledního z nich se stala Česká spořitelna, jedna z nejvyužívanějších bank v zemi. O útoku vás informoval server Měšec.cz a k dispozici byla také oficiální tisková zpráva z banky.

Zajímavostí tohoto útoku bylo, že ačkoliv se podvodník pokoušel dostat k přihlašovacím údajům do elektronického bankovnictví aplikace Servis24, nešlo v jeho případě o klasický útok metodou phishingu, ale byla také jiná z digitálně zločineckých technik – zvaná pharming. Ta je poměrně zajímavá a v ČR relativně řídká. Přitom dokáže poškodit i ty uživatele, kteří jsou poučeni o zásadách elektronické bezpečnosti a běžnému útočníkovi by „na špek“ prostě neskočili. Podívejme se na to, jak pharming funguje a proč je třeba se ho bát.

Hurá na údaje

Cílem činnosti internetových podvodníků je v případě útoků proti aplikacím oslovit jejich regulérní uživatele. Podvodník z uživatele elektronického bankovnictví, platebního systému, aukčního serveru, obchodu a podobně, nejprve vymámí jeho přihlašovací údaje. Díky tomu se pak může do příslušné aplikace přihlásit sám a získat benefit. Prakticky vzato vám může vybrat účet, okopírovat e-maily, ukrást identitu a vydávat se za vás.

Jak se uživatelé Internetu stávají více a více erudovanými v oblasti bezpečnosti, útočníkům se komplikuje přístup k jejich údajům. Nejstarší podvod zvaný phishing (česky asi nejlépe „rhybaření“) se stává neúčinným.

Tip: Zajímají vás názory člověka, který se vykrádáním účtů přes Internet živí? Přečtěte si exkluzivní rozhovor s crackerem, podle něhož na podvodné e-maily naletí až dvacet procent příjemců.

Na počátku tohoto druhu zločinnosti v zásadě stačilo, aby útočník poslal oběti e-mail, ve kterém se vydával za banku. Pod smyšlenou historkou žádal „ověření“ přihlašovacích údajů k elektronickému, nebo třeba telefonnímu bankovnictví. E-mail vypadal důvěryhodně, a mnozí uživatelé na něj skutečně odpověděli v domnění, že komunikují s bankou (nebo třeba s eBay). V současnosti ale málokterý uživatel na podobný e-mail odpoví, aniž by se pozastavil nad jeho pravostí. Prostě proto, že vzdělávání uživatelů v bezpečnosti je prioritou nejenom bank, ale také zaměstnavatelů, je to součást základních kurzů pro oblast IT a věnují se mu rovněž obecná média.

Takže útočníci přešli k sofistikovanější metodě „balamutění“. Přestali po obětích požadovat údaje do e-mailu a místo toho připravují napodobeniny autentických webových aplikací. Podvodné e-maily obsahují odkaz na stránky, které jsou kopiemi reálného rozhraní, například bankovnictví, a mohou dokonce odkazovat na skutečné servery provozovatelů služeb. Jediný rozdíl spočívá v tom, že uživatel svá přihlašovací data neposílá organizaci, jejíž služby potřebuje, ale podvodníkovi. Čím zdařilejší je podvodníkova stránka a e-mail, tím vyšší je pravděpodobnost úspěchu.

I proti této metodě existuje laicky snadno zapamatovatelná metoda ochrany. Neklikat na odkazy v e-mailech, ale vždy zadávat URL autentické aplikace do adresního řádku prohlížeče. Tím je možnost, že by otevřel server podvodníka a následně mu sdělil své důvěrné údaje v případě klasického útoku metodou phishing, v podstatě eliminována. Ochrana uživatele je dále posílena tím, že mnohé poštovní aplikace ve výchozím nastavení odkazy v e-mailech jednoduše blokují a laika tak k ručnímu zadání adresy nepřímo nutí.

Inovace

Internetoví zločinci tak přešli k mnohem sofistikovanější metodě získávání přihlašovacích informací z uživatelů, tato metoda se jmenuje pharming („pharmaření“) a má dvě podoby. První z nich je značně efektivní, ale také pro útočníka neobyčejně obtížná, což její užití omezuje. Druhá je jednodušší, nicméně se jí lze snáze bránit. Popišme si obě.

Pharming v „globálním“ měřítku spočívá v tom, že útočník neoslovuje přímo jednotlivé uživatele služby, ale napadne vybraný DNS server. DNS (Domain Name System) je hierarchická databáze, která udržuje seznam internetových domén a příslušných DNS adres. Pokud se podvodníkovi zdaří změnit záznam v hůře zabezpečeném DNS serveru, pak všichni uživatelé, kteří jsou napojeni na tento DNS server a zadají do adresního řádku prohlížeče správnou adresu třeba internetového bankovnictví, dostanou falešnou stránku. Jestliže je tato falešná stránka dobře vypracovaná, pak je šance, že by uživatel, byť i erudovaný, na podvod přišel, velmi nízká. Musel by totiž kontrolovat certifikát, kterým je podepsána, a kterým se šifruje přenos dat. Tento certifikát se všemi náležitostmi není podvodník schopen padělat, nicméně může navodit stav, kdy je z pohledu uživatele, který netrvá na velmi podrobném průzkumu, vše v pořádku.

Druhá metoda, můžeme ji nazvat lokální pharming, je založena na útoku proti jednotlivým počítačům. PC s operačními systémy Windows obsahují takzvaný hosts soubor, který funguje obdobně jako DNS server. Tedy, obsahuje IP adresy a korespondující domény. Jestliže se útočníkovi podaří do tohoto souboru zapsat adresu své podvodné stránky a doménou bankovnictví, pak je efekt pro uživatele stejný jako v předchozím případě. Tedy i po zadání korektní URL adresy je zobrazena podvodná stránka a přihlašovací údaje skončí v rukách zločince.

První metoda je nezávislá na klientských počítačích, nicméně je potřeba zdolat ochranu DNS serveru. Vzhledem k tomu, že DNS tvoří páteř Internetu, jsou tyto servery jedny z nejvíce chráněných. Objevit v nich zneužitelnou chybu a využít ji, aniž by si toho správci všimli, je extrémně obtížná záležitost. A tak se útočníci uchylují ke druhé metodě.

Pharming až do vašeho PC

Změna souboru hostitelů je možná pouze tehdy, když má podvodník možnost do něj zapisovat. To webová stránka či e-mail neumí, takže přichází na řadu škodlivé kódy. Pokud útočník do PC nainstaluje trojského koně, který změnu provede, v ideálním případě na základě dálkového povelu a opakovaně, pak má vyhráno. Trojský kůň se může maskovat za doplněk softwaru, může být přibalen k reálným aplikacím, může být poslán v příloze e-mailu, a nebo si jej oběť může stáhnout z webu na základě podvržené zprávy. Po úspěšném nainstalování a změně seznamu hostitelů následuje efekt, který jsem popsal výše, krádež přihlašovacích dat a následně i třeba peněz může být dokonána.

Ochrana

Jak je zřejmé, pharming je podstatně nebezpečnější než phishing. Lze jím oklamat i zkušeného uživatele webových služeb. Nemusí jej odhalit dokonce ani ochrana před podvodnými weby, jež je součástí posledních verzí webových prohlížečů. Nicméně to, že je boj proti němu obtížnější, neznamená, že by bylo nutné jej vzdát.

Možnosti správců uživatelských PC a samotných uživatelů postupovat proti pharmingu založenému na napadení DNS serveru jsou v podstatě minimální. Ochrana proti lokální formě útoku je založena především na aktivním, správně nastaveném a hlavně aktuálním antivirovém programu. Ten by měl kontrolovat nejen všechny soubory posílané elektronickou poštou, ale také vše, co je spouštěno a stahováno z webu. Útočník se může snažit škodlivý kód zabalit do šifrovaného archivu, takže antivirus musí kontrolovat archivy v okamžiku jejich otevření.

Druhým krokem ochrany je samotný soubor s názvy hostitelů. Některé bezpečnostní aplikace jej umožňují uzamknout a chránit před změnou. Takže i kdyby došlo k instalaci trojského koně, tento se seznamem hostitelů nic nezmůže. Nevýhodou této metody je, že do seznamu potřebují zapisovat také některé regulérní aplikace, služby s webovým rozhraním spouštěné z místního počítače a některé síťové technologie. Ty je pro některé uživatele obtížné odlišit od škodlivého kódu a uzamčení souboru s hostiteli snižuje použitelnost regulérních programů.

Třetí možností, která je vhodná spíše pro technicky zdatnější a aktivní uživatele, je používání nástrojů, které zobrazují doplňující informace o právě zobrazovaných webových stránkách. Například produkt Netcraft Toolbar byl již na našem serveru zmiňován ve starším článku popisujícím technickou podstatu pharmingu.

Moderní webové prohlížeče obsahují už zmíněnou ochranu před podvodnými stránkami. Aby tato ochrana fungovala, musí být stránka odhalena a označena za nebezpečnou. Z tohoto důvodu nelze zejména v případě útoků, které jsou směřovány na konkrétní uživatele na malém území (například elektronického bankovnictví České spořitelny v ČR), spoléhat na její dostatečnou rychlost.

CIF25_SE_terc

Posledním (ale vlastně spíše prvním) důležitým faktorem je informování uživatelů a určitá hygiena práce s počítačem. Uživatelé by měli vědět, že nesmí bezhlavě klikat na odkazy v e-mailech, stahovat z Internetu neznámé aplikace, i kdyby se tvářily sebelépe, a že banka (ani jiná služba) jim kvůli „kontrole“ údajů nikdy žádný e-mail nepošle.

Pharming je nebezpečný, ale lze jej zvládnout obdobně jako phishing nebo červy rozesílané e-mailem. Tím nejdůležitějším je ale nepodcenit problém a hlavně co nejvyšší informovanost koncových uživatelů.

Setkali jste se již osobně s pharmingem?

Autor článku

Autor je sociolog, odborný publicista, poradce, a lektor.

'; document.getElementById('preroll-iframe').onload = function () { setupIframe(); } prerollContainer = document.getElementsByClassName('preroll-container-iframe')[0]; } function setupIframe() { prerollDocument = document.getElementById('preroll-iframe').contentWindow.document; let el = prerollDocument.createElement('style'); prerollDocument.head.appendChild(el); el.innerText = "#adContainer>div:nth-of-type(1),#adContainer>div:nth-of-type(1) > iframe { width: 99% !important;height: 99% !important;max-width: 100%;}#videoContent,body{ width:100vw;height:100vh}body{ font-family:'Helvetica Neue',Arial,sans-serif}#videoContent{ overflow:hidden;background:#000}#adMuteBtn{ width:35px;height:35px;border:0;background:0 0;display:none;position:absolute;fill:rgba(230,230,230,1);bottom:20px;right:25px}"; videoContent = prerollDocument.getElementById('contentElement'); videoContent.style.display = 'none'; videoContent.volume = 1; videoContent.muted = false; const playPromise = videoContent.play(); if (playPromise !== undefined) { playPromise.then(function () { console.log('PREROLL sound allowed'); // setUpIMA(true); videoContent.volume = 1; videoContent.muted = false; setUpIMA(); }).catch(function () { console.log('PREROLL sound forbidden'); videoContent.volume = 0; videoContent.muted = true; setUpIMA(); }); } } function setupDimensions() { prerollWidth = Math.min(iinfoPrerollPosition.offsetWidth, 480); prerollHeight = Math.min(iinfoPrerollPosition.offsetHeight, 320); } function setUpIMA() { google.ima.settings.setDisableCustomPlaybackForIOS10Plus(true); google.ima.settings.setLocale('cs'); google.ima.settings.setNumRedirects(10); // Create the ad display container. createAdDisplayContainer(); // Create ads loader. adsLoader = new google.ima.AdsLoader(adDisplayContainer); // Listen and respond to ads loaded and error events. adsLoader.addEventListener( google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, onAdsManagerLoaded, false); adsLoader.addEventListener( google.ima.AdErrorEvent.Type.AD_ERROR, onAdError, false); // An event listener to tell the SDK that our content video // is completed so the SDK can play any post-roll ads. const contentEndedListener = function () { adsLoader.contentComplete(); }; videoContent.onended = contentEndedListener; // Request video ads. const adsRequest = new google.ima.AdsRequest(); adsRequest.adTagUrl = iinfoVastUrls[iinfoVastUrlIndex]; console.log('Preroll advert: ' + iinfoVastUrls[iinfoVastUrlIndex]); videoContent.muted = false; videoContent.volume = 1; // Specify the linear and nonlinear slot sizes. This helps the SDK to // select the correct creative if multiple are returned. // adsRequest.linearAdSlotWidth = prerollWidth; // adsRequest.linearAdSlotHeight = prerollHeight; adsRequest.nonLinearAdSlotWidth = 0; adsRequest.nonLinearAdSlotHeight = 0; adsLoader.requestAds(adsRequest); } function createAdDisplayContainer() { // We assume the adContainer is the DOM id of the element that will house // the ads. prerollDocument.getElementById('videoContent').style.display = 'none'; adDisplayContainer = new google.ima.AdDisplayContainer( prerollDocument.getElementById('adContainer'), videoContent); } function unmutePrerollAdvert() { adVolume = !adVolume; if (adVolume) { adsManager.setVolume(0.3); prerollDocument.getElementById('adMuteBtn').innerHTML = ''; } else { adsManager.setVolume(0); prerollDocument.getElementById('adMuteBtn').innerHTML = ''; } } function onAdsManagerLoaded(adsManagerLoadedEvent) { // Get the ads manager. const adsRenderingSettings = new google.ima.AdsRenderingSettings(); adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true; adsRenderingSettings.loadVideoTimeout = 12000; // videoContent should be set to the content video element. adsManager = adsManagerLoadedEvent.getAdsManager(videoContent, adsRenderingSettings); // Add listeners to the required events. adsManager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, onAdError); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED, onContentPauseRequested); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED, onContentResumeRequested); adsManager.addEventListener( google.ima.AdEvent.Type.ALL_ADS_COMPLETED, onAdEvent); // Listen to any additional events, if necessary. adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.STARTED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.COMPLETE, onAdEvent); playAds(); } function playAds() { // Initialize the container. Must be done through a user action on mobile // devices. videoContent.load(); adDisplayContainer.initialize(); // setupDimensions(); try { // Initialize the ads manager. Ad rules playlist will start at this time. adsManager.init(1920, 1080, google.ima.ViewMode.NORMAL); // Call play to start showing the ad. Single video and overlay ads will // start at this time; the call will be ignored for ad rules. adsManager.start(); // window.addEventListener('resize', function (event) { // if (adsManager) { // setupDimensions(); // adsManager.resize(prerollWidth, prerollHeight, google.ima.ViewMode.NORMAL); // } // }); } catch (adError) { // An error may be thrown if there was a problem with the VAST response. // videoContent.play(); } } function onAdEvent(adEvent) { const ad = adEvent.getAd(); console.log('Preroll event: ' + adEvent.type); switch (adEvent.type) { case google.ima.AdEvent.Type.LOADED: if (!ad.isLinear()) { videoContent.play(); } prerollDocument.getElementById('adContainer').style.width = '100%'; prerollDocument.getElementById('adContainer').style.maxWidth = '640px'; prerollDocument.getElementById('adContainer').style.height = '360px'; break; case google.ima.AdEvent.Type.STARTED: window.addEventListener('scroll', onActiveView); if (ad.isLinear()) { intervalTimer = setInterval( function () { // Example: const remainingTime = adsManager.getRemainingTime(); // adsManager.pause(); }, 300); // every 300ms } prerollDocument.getElementById('adMuteBtn').style.display = 'block'; break; case google.ima.AdEvent.Type.ALL_ADS_COMPLETED: if (ad.isLinear()) { clearInterval(intervalTimer); } if (prerollLastError === 303) { playYtVideo(); } break; case google.ima.AdEvent.Type.COMPLETE: if (ad.isLinear()) { clearInterval(intervalTimer); } playYtVideo(); break; } } function onAdError(adErrorEvent) { console.log(adErrorEvent.getError()); prerollLastError = adErrorEvent.getError().getErrorCode(); if (!loadNext()) { playYtVideo(); } } function loadNext() { iinfoVastUrlIndex++; if (iinfoVastUrlIndex < iinfoVastUrls.length) { iinfoPrerollPosition.remove(); playPrerollAd(); } else { return false; } adVolume = 1; return true; } function onContentPauseRequested() { videoContent.pause(); } function onContentResumeRequested() { videoContent.play(); } function onActiveView() { if (prerollContainer) { const containerOffset = prerollContainer.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight/1 && containerOffset.bottom > 0.0) { if (prerollPaused) { adsManager.resume(); prerollPaused = false; } return true; } else { if (!prerollPaused) { adsManager.pause(); prerollPaused = true; } } } return false; } function playYtVideo() { iinfoPrerollPosition.remove(); youtubeIframe.style.display = 'block'; youtubeIframe.src += '&autoplay=1&mute=1'; } }
Upozorníme vás na články, které by vám neměly uniknout (maximálně 2x týdně).
'; document.getElementById('outstream-iframe').onload = function () { setupIframe(); } replayScreen = document.getElementById('iinfoOutstreamReplay'); iinfoOutstreamPosition = document.getElementById('iinfoOutstreamPosition'); outstreamContainer = document.getElementsByClassName('outstream-container')[0]; setupReplayScreen(); } function setupIframe() { outstreamDocument = document.getElementById('outstream-iframe').contentWindow.document; let el = outstreamDocument.createElement('style'); outstreamDocument.head.appendChild(el); el.innerText = "#adContainer>div:nth-of-type(1),#adContainer>div:nth-of-type(1) > iframe { width: 99% !important;height: 99% !important;max-width: 100%;}#videoContent,body{ width:100vw;height:100vh}body{ font-family:'Helvetica Neue',Arial,sans-serif}#videoContent{ overflow:hidden;background:#000}#adMuteBtn{ width:35px;height:35px;border:0;background:0 0;display:none;position:absolute;fill:rgba(230,230,230,1);bottom:-5px;right:25px}"; videoContent = outstreamDocument.getElementById('contentElement'); videoContent.style.display = 'none'; videoContent.volume = 1; videoContent.muted = false; if ( location.href.indexOf('rejstriky.finance.cz') !== -1 || location.href.indexOf('finance-rejstrik') !== -1 || location.href.indexOf('firmy.euro.cz') !== -1 || location.href.indexOf('euro-rejstrik') !== -1 || location.href.indexOf('/rejstrik/') !== -1 || location.href.indexOf('/rejstrik-firem/') !== -1) { outstreamDirectPlayed = true; soundAllowed = true; iinfoVastUrlIndex = 0; } if (!outstreamDirectPlayed) { console.log('OUTSTREAM direct'); setUpIMA(true); } else { if (soundAllowed) { const playPromise = videoContent.play(); if (playPromise !== undefined) { playPromise.then(function () { console.log('OUTSTREAM sound allowed'); setUpIMA(false); }).catch(function () { console.log('OUTSTREAM sound forbidden'); renderBanner(); }); } } else { renderBanner(); } } } function getWrapper() { let articleWrapper = document.querySelector('.rs-outstream-placeholder'); // Outstream Placeholder from RedSys manipulation if (articleWrapper && articleWrapper.style.display !== 'block') { articleWrapper.innerHTML = ""; articleWrapper.style.display = 'block'; } // Don't render OutStream on homepages if (articleWrapper === null) { if (document.querySelector('body.p-index')) { return null; } } if (articleWrapper === null) { articleWrapper = document.getElementById('iinfo-outstream'); } if (articleWrapper === null) { articleWrapper = document.querySelector('.layout-main__content .detail__article p:nth-of-type(6)'); } if (articleWrapper === null) { // Euro, Autobible, Zdravi articleWrapper = document.querySelector('.o-article .o-article__text p:nth-of-type(6)'); } if (articleWrapper === null) { articleWrapper = document.getElementById('sidebar'); } if (!articleWrapper) { console.error("Outstream wrapper of article was not found."); } return articleWrapper; } function setupDimensions() { outstreamWidth = Math.min(iinfoOutstreamPosition.offsetWidth, 480); outstreamHeight = Math.min(iinfoOutstreamPosition.offsetHeight, 320); } /** * Sets up IMA ad display container, ads loader, and makes an ad request. */ function setUpIMA(direct) { google.ima.settings.setDisableCustomPlaybackForIOS10Plus(true); google.ima.settings.setLocale('cs'); google.ima.settings.setNumRedirects(10); // Create the ad display container. createAdDisplayContainer(); // Create ads loader. adsLoader = new google.ima.AdsLoader(adDisplayContainer); // Listen and respond to ads loaded and error events. adsLoader.addEventListener( google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, onAdsManagerLoaded, false); adsLoader.addEventListener( google.ima.AdErrorEvent.Type.AD_ERROR, onAdError, false); // An event listener to tell the SDK that our content video // is completed so the SDK can play any post-roll ads. const contentEndedListener = function () { adsLoader.contentComplete(); }; videoContent.onended = contentEndedListener; // Request video ads. const adsRequest = new google.ima.AdsRequest(); if (direct) { adsRequest.adTagUrl = directVast; console.log('Outstream DIRECT CAMPAING advert: ' + directVast); videoContent.muted = true; videoContent.volume = 0; outstreamDirectPlayed = true; } else { adsRequest.adTagUrl = iinfoVastUrls[iinfoVastUrlIndex]; console.log('Outstream advert: ' + iinfoVastUrls[iinfoVastUrlIndex]); videoContent.muted = false; videoContent.volume = 1; } // Specify the linear and nonlinear slot sizes. This helps the SDK to // select the correct creative if multiple are returned. // adsRequest.linearAdSlotWidth = outstreamWidth; // adsRequest.linearAdSlotHeight = outstreamHeight; adsRequest.nonLinearAdSlotWidth = 0; adsRequest.nonLinearAdSlotHeight = 0; adsLoader.requestAds(adsRequest); } function setupReplayScreen() { replayScreen.addEventListener('click', function () { iinfoOutstreamPosition.remove(); iinfoVastUrlIndex = 0; outstreamInit(); }); } /** * Sets the 'adContainer' div as the IMA ad display container. */ function createAdDisplayContainer() { // We assume the adContainer is the DOM id of the element that will house // the ads. outstreamDocument.getElementById('videoContent').style.display = 'none'; adDisplayContainer = new google.ima.AdDisplayContainer( outstreamDocument.getElementById('adContainer'), videoContent); } function unmuteAdvert() { adVolume = !adVolume; if (adVolume) { adsManager.setVolume(0.3); outstreamDocument.getElementById('adMuteBtn').innerHTML = ''; } else { adsManager.setVolume(0); outstreamDocument.getElementById('adMuteBtn').innerHTML = ''; } } /** * Loads the video content and initializes IMA ad playback. */ function playAds() { // Initialize the container. Must be done through a user action on mobile // devices. videoContent.load(); adDisplayContainer.initialize(); // setupDimensions(); try { // Initialize the ads manager. Ad rules playlist will start at this time. adsManager.init(1920, 1080, google.ima.ViewMode.NORMAL); // Call play to start showing the ad. Single video and overlay ads will // start at this time; the call will be ignored for ad rules. adsManager.start(); // window.addEventListener('resize', function (event) { // if (adsManager) { // setupDimensions(); // adsManager.resize(outstreamWidth, outstreamHeight, google.ima.ViewMode.NORMAL); // } // }); } catch (adError) { // An error may be thrown if there was a problem with the VAST response. // videoContent.play(); } } /** * Handles the ad manager loading and sets ad event listeners. * @param { !google.ima.AdsManagerLoadedEvent } adsManagerLoadedEvent */ function onAdsManagerLoaded(adsManagerLoadedEvent) { // Get the ads manager. const adsRenderingSettings = new google.ima.AdsRenderingSettings(); adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true; adsRenderingSettings.loadVideoTimeout = 12000; // videoContent should be set to the content video element. adsManager = adsManagerLoadedEvent.getAdsManager(videoContent, adsRenderingSettings); // Add listeners to the required events. adsManager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, onAdError); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED, onContentPauseRequested); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED, onContentResumeRequested); adsManager.addEventListener( google.ima.AdEvent.Type.ALL_ADS_COMPLETED, onAdEvent); // Listen to any additional events, if necessary. adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.STARTED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.COMPLETE, onAdEvent); playAds(); } /** * Handles actions taken in response to ad events. * @param { !google.ima.AdEvent } adEvent */ function onAdEvent(adEvent) { // Retrieve the ad from the event. Some events (for example, // ALL_ADS_COMPLETED) don't have ad object associated. const ad = adEvent.getAd(); console.log('Outstream event: ' + adEvent.type); switch (adEvent.type) { case google.ima.AdEvent.Type.LOADED: // This is the first event sent for an ad - it is possible to // determine whether the ad is a video ad or an overlay. if (!ad.isLinear()) { // Position AdDisplayContainer correctly for overlay. // Use ad.width and ad.height. videoContent.play(); } outstreamDocument.getElementById('adContainer').style.width = '100%'; outstreamDocument.getElementById('adContainer').style.maxWidth = '640px'; outstreamDocument.getElementById('adContainer').style.height = '360px'; break; case google.ima.AdEvent.Type.STARTED: window.addEventListener('scroll', onActiveView); // This event indicates the ad has started - the video player // can adjust the UI, for example display a pause button and // remaining time. if (ad.isLinear()) { // For a linear ad, a timer can be started to poll for // the remaining time. intervalTimer = setInterval( function () { // Example: const remainingTime = adsManager.getRemainingTime(); // adsManager.pause(); }, 300); // every 300ms } outstreamDocument.getElementById('adMuteBtn').style.display = 'block'; break; case google.ima.AdEvent.Type.ALL_ADS_COMPLETED: if (ad.isLinear()) { clearInterval(intervalTimer); } if (outstreamLastError === 303) { if (isBanner) { renderBanner(); } else { replayScreen.style.display = 'flex'; } } break; case google.ima.AdEvent.Type.COMPLETE: // This event indicates the ad has finished - the video player // can perform appropriate UI actions, such as removing the timer for // remaining time detection. if (ad.isLinear()) { clearInterval(intervalTimer); } if (isBanner) { renderBanner(); } else { replayScreen.style.display = 'flex'; } break; } } /** * Handles ad errors. * @param { !google.ima.AdErrorEvent } adErrorEvent */ function onAdError(adErrorEvent) { // Handle the error logging. console.log(adErrorEvent.getError()); outstreamLastError = adErrorEvent.getError().getErrorCode(); if (!loadNext()) { renderBanner(); } } function renderBanner() { if (isBanner) { console.log('Outstream: Render Banner'); iinfoOutstreamPosition.innerHTML = ""; iinfoOutstreamPosition.style.height = "330px"; iinfoOutstreamPosition.appendChild(bannerDiv); } else { console.log('Outstream: Banner is not set'); } } function loadNext() { iinfoVastUrlIndex++; if (iinfoVastUrlIndex < iinfoVastUrls.length) { iinfoOutstreamPosition.remove(); outstreamInit(); } else { return false; } adVolume = 1; return true; } /** * Pauses video content and sets up ad UI. */ function onContentPauseRequested() { videoContent.pause(); // This function is where you should setup UI for showing ads (for example, // display ad timer countdown, disable seeking and more.) // setupUIForAds(); } /** * Resumes video content and removes ad UI. */ function onContentResumeRequested() { videoContent.play(); // This function is where you should ensure that your UI is ready // to play content. It is the responsibility of the Publisher to // implement this function when necessary. // setupUIForContent(); } function onActiveView() { if (outstreamContainer) { const containerOffset = outstreamContainer.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight/1 && containerOffset.bottom > 0.0) { if (outstreamPaused) { adsManager.resume(); outstreamPaused = false; } return true; } else { if (!outstreamPaused) { adsManager.pause(); outstreamPaused = true; } } } return false; } let outstreamInitInterval; if (typeof cpexPackage !== "undefined") { outstreamInitInterval = setInterval(tryToInitializeOutstream, 100); } else { const wrapper = getWrapper(); if (wrapper) { let outstreamInitialized = false; window.addEventListener('scroll', () => { if (!outstreamInitialized) { const containerOffset = wrapper.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight / 1 && containerOffset.bottom > 0.0) { outstreamInit(); outstreamInitialized = true; } } }); } } function tryToInitializeOutstream() { const wrapper = getWrapper(); if (wrapper) { const containerOffset = wrapper.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight / 1 && containerOffset.bottom > 0.0) { if (cpexPackage.adserver.displayed) { clearInterval(outstreamInitInterval); outstreamInit(); } } } else { clearInterval(outstreamInitInterval); } } }
OSZAR »