Názory k článku Let's Encrypt začíná validovat žádosti o certifikáty z různých míst

  • Článek je starý, nové názory již nelze přidávat.
  • 19. 2. 2020 8:07

    Filip Jirsák
    Stříbrný podporovatel

    Než zahušťovat validační body tak, aby validace vždy šla i přes peering, bylo by podle mne užitečnější umět omezit použité validační metody – draft-ietf-acme-caa-04. Pokud bych mohl omezit metodu na dns-01 a měl na doméně DNSSEC, možnosti útočníků tím dost omezím.

  • 19. 2. 2020 9:11

    Ondřej Caletka
    Zlatý podporovatel

    Ideálně samozřejmě obojí. Možnost použití CAA omezení pro uvědomělé a hustou síť validačních bodů pro všechny ostatní, kterým stačí, že to nějak funguje a kterých bude vždycky většina.

  • 19. 2. 2020 11:42

    Miroslav Šilhavý

    To je sice pravda, ale v praxi pokulhává. Jednotlivci i malé firmy nemají správu DNS pevně v rukou. Velká část (možná i početně převážná) to má tak: "Kde máte DNS?", "Já nevím.", "Kdo vám zařizoval doménu?", "Předpředminulý ajťák, musím se podívat, jak se jmenoval. Nebo to zařizovala ta firma, co nám dodávala stránky?".

    Hrnout ověření víc a víc k DNS smysl dává, ale samo o sobě to nepřinese velkou změnu ve faktickém stavu. V první fázi to vyvolá zděšení a tlak na držitele domén, aby si to dali do pořádku. A tak budou dávat "do pořádku" něco, co léta funguje a neměli a nemají žádnou přirozenou potřebu to dělat. Další slabinou, kterou nikdo neřeší, je zabezpečení samotných služeb zajišťujících registraci domén a správu DNS. Přitom na zabezpečení a auditování těchto služeb by se dal vyvinout tlak nejjednodušeji: chceš být registrátorem, podrob se pravidlům bezpečnosti. To se ale zatím neděje, nebo ne dostatečně.

    Celá filozofie DV certifikátů je pochybná. Na místo OV certifikátů, které sice něco stály, ale probíhalo aspoň nějaké opravdové ověření, máme tu certifikáty ověřené sice dokonale, ale v řetězci úkonů, na jehož počátku je díra velká jak vrata.

    Zahušťovat validační body proto dává smysl - nepřinese to moc komplikací a výsledek bude o něco lepší. Přechod výhradně na dns-01 by bezpečnost nezvýšil nijak výrazně v praxi. Naopak by způsobil problémy při ověřování certifikátů pro delegované systémy. V tu chvíli by musel držitel domény nejen delegovat systém (FQDN) na jiného provozovatele, ale ještě vyřešit delegování mechanismu ověření dns-01.

  • 19. 2. 2020 12:02

    Filip Jirsák
    Stříbrný podporovatel

    Zapomněl jste na to, že celý web je na DNS závislý.

    O bezpečnost DNS se provozovatel webu musí stejně postarat, bez ohledu na certifikáty. DV certifikáty z principu nejde udělat bezpečnější, než je DNS. OV/EV certifikáty sice bezpečnější udělat lze, ale pořád to bude tak, že při ovládnutí DNS zóny nebudete moci vystavit falešný web s OV/EV certifikátem, ale můžete vystavit falešný web s DV certifikátem nebo web prostě vypnout. Pochybuju o tom, že by vlastníky OV/EV certifikátů vypnutí jejich webů nijak netrápilo. Nehledě na to, že dnes v běžném prohlížeči nejde odlišit ani EV certifikát, takže k vytvoření falešného webu DV certifikát stačí.

    Certifikační autorita na zabezpečení DNS nemá žádný vliv – nanejvýš může validovat DNSSEC. To, aby měl bezpečné DNS, si musí každý provozovatel webu pohlídat sám – což je přesně to, po čem voláte v diskusích o webových prohlížečích.

    Já jsem popisoval zlepšení ve smyslu „kdo chce lepší zabezpečení, má možnost“. Vy argumentujete tím, že když si to nezabezpečí lépe všichni, nemá smysl dávat tu možnost nikomu. Když si někdo nezabezpečí svůj blogísek, nebudeme přece dávat nástroj na lepší zabezpečení nikomu, ani bance. Já vám to neberu, je to váš názor, ale nepovažuju takový přístup za rozumný.

    Celá filozofie DV certifikátů je pochybná.
    S tím souhlasím, DV certifikáty by vůbec neměly existovat, jenom duplikují informace, které už jsou v DNS. Nicméně věrohodné ověření domény potřebujete i pro OV a EV serverové certifikáty. A dokud tu DV certifikáty jsou, měli bychom se snažit zabezpečit i ty.

    výsledek bude o něco lepší
    Řešíte problém únosu DNS zóny, a tento problém zahuštění validačních bodů nijak neřeší.

    Přechod výhradně na dns-01
    To je ovšem čistě váš výmysl, já jsem o přechodu výhradně na dns-01 nic nepsal.

    V tu chvíli by musel držitel domény nejen delegovat systém (FQDN) na jiného provozovatele, ale ještě vyřešit delegování mechanismu ověření dns-01.
    Jo, přidat k jednomu CNAME záznamu ještě druhý CNAME záznam bude nepřekonatelný problém.

  • 19. 2. 2020 12:59

    Miroslav Šilhavý

    Vše co píšete, je samozřejmě pravdivé. Jen pomíjíte tu praktickou část problému - tedy, že jeden problém vyřešíte správně, ale druhý, latentní, vyeskalujete do aktuního.

  • 19. 2. 2020 13:26

    Filip Jirsák
    Stříbrný podporovatel

    Validace serverových certifikátů bude na DNS závislá vždy. Buď je dnes DNS nejslabším článkem, pak by útočníci už dnes útočili přes DNS a zároveň by se hledala opatření. Nebo DNS není nejslabším článkem, pak je potřeba řešit přednostně ta slabší místa. Nemá smysl naříkat nad tím, že až vyřešíte ta nejslabší místa, stane se nejslabším místem DNS – vždycky bude nějaké nejslabší místo a to je pak potřeba řešit.

  • 19. 2. 2020 13:55

    Miroslav Šilhavý

    Ve skutečnosti nemáme žádné údaje o tom, jestli existují pokusy získat certifikát prostřednictvím slabin v DNS správě, přesto to můžeme považovat za riziko a odhadovat jeho závažnost. Stejně tak můžeme odhadovat, jestli se nějakým opatřením zvýší buďto závažnost nebo urgentnost rizika.

    Ve Vašem návrhu se nezvyšuje závažnost (ta zůstává neměnná), ale urgentnost se pravděpodobně zvýší. Dál lze odhadovat (předpokládat), že po překročení určité hranice začne být toto riziko plošně zneužívané. To způsobí další problémy v praxi.

    Neříkám, že se nic nemá dělat, to mě nechápete správně. Říkám, že k takovým změnám, jako navrhujete, je potřeba zvážit i ty důsledky v praxi a případně zvolit jinou cestu, jak se postupně přiblížit k cíli.

    Vykosit celou oblast tím, že namalujeme na papír, jak by to mělo být správně a vynutíme to, to umí každý.

  • 19. 2. 2020 14:47

    Filip Jirsák
    Stříbrný podporovatel

    Takže když nevíte, jestli existují snahy zneužívat slabiny ve správě DNS, budete se tvářit, že snahy neexistují a že se nemáme snažit tu správu více zabezpečit, protože tím bychom na ty slabiny upozornili. Zajímavá teorie. A neměl byste tedy především vy o těch slabinách mlčet? Tím přece také potenciálním útočníkům ukazujete cestu.

    Já si myslím, že je potřeba především mít k dispozici ty nástroje pro zabezpečení. Pokud je pak někdo nepoužije, je to jeho problém. Nesouhlasím s vaším přístupem, že radši nebudeme bezpečnější nástroje vytvářet, protože tím bychom na nedostatky v zabezpečení upozornili. Security through obscurity totiž nefunguje. A až to útočníci začnou zneužívat, bude pozdě na to nějaké nástroje teprve začít vytvářet. Vy se chcete bránit neschopným útočníkům, kteří nevědí, na co mají útočit, já se chci bránit těm schopným – obrana proti nim totiž zahrnuje i obranu proti těm neschopným.

  • 19. 2. 2020 17:03

    Miroslav Šilhavý

    @Filip Jirsák:

    Tlačíte to do extrému. Tlačit na zlepšení není totéž, jako bez ohledu na stav věcí to vynutit. Je potřeba jít oběma cestami. Na jedné straně zlepšovat stav a zvyšovat využitelnost ideální cesty, ale na druhé straně poskytovat nástroje, které situaci zlepšují i tam, kde stav ideální (ještě) není. Ideální auto je s ABS, ESR, airbagy a dalšími pomocníky. Přesto není myslitelné zakázat provoz všech i starších aut, které to nesplňují - maximálně se může zavést direktiva, že nová auta už musí být vybavená. Proč? Protože je bezohledné chtít, aby si ti, co za auto zaplatili, museli jen tak vyměnit za nové, je potřeba na ně brát ohled.

  • 19. 2. 2020 17:50

    Filip Jirsák
    Stříbrný podporovatel

    Miroslav Šilhavý: Píšete sice hezky, ale zcela mimo kontext této diskuse. O žádném vynucování totiž nebyla řeč.

  • 19. 2. 2020 17:08

    Hynek

    Je rozdíl, jestli "autorita toleruje výpadek jednoho ze vzdálených validačních uzlů" nebo jestli toleruje i jednu nekonzistentní odpověď neodpovídající požadavku o certifikát. To z textu není jasné. Pokud je tolerován opravdu jen výpadek, nikoli nekonzistence, pak je to odolnější proti MiM a útočník by jednak musel napíchnout kabel, kterým chodí spojení od N -1 serverů a ještě by musel blokovat jedno spojení. Na druhou stranu by hrozilo DoS vymýšlením falešných odpovědí na jedné trase. Předpokládám, že tolerování výpadku je okamžité zatímco nekonzístence by mohla znamenat prodloužení procesu ověřování.

    Podle kapitoly "Replay Protection" v RFC 8555 se zdá, že na vícero ověřování mysleli důkladně. Kdo z nás má kapacitu si číst celý dokument.

    19. 2. 2020, 17:10 editováno autorem komentáře

'; 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 »